Получение временного адреса - требуется обходной путь

Я сталкиваюсь с предупреждением GCC, которое я хочу исправить. В основном я передаю методу указатель на локальную переменную, что в моем случае совершенно нормально. Я понимаю, почему компилятор говорит мне, что это потенциальная проблема, но в моем случае это нормально.

Как я могу обойти это в локальном пространстве? Если передать -fpermissive при компиляции, мне не удастся найти будущие проблемы. Я хочу исправить эту конкретную проблему или обойти ее.

Код доступен здесь:

#include <cstdio>

class Integer{
public:
    Integer(int i ){ v = i; };
    int value(){ return v; };
private:
    int v;
};

int foo(Integer *i);

int main()
{
    foo( &Integer(12) );
}

int foo(Integer *i)
{
    std::printf("Integer = %d\n", i->value());
}

И компиляция дает мне:

$ g++ test-reference.cpp -O test-reference
test-reference.cpp: In function ‘int main()’:
test-reference.cpp:15:18: error: taking address of temporary [-fpermissive]

$ g++ --version
g++ (Ubuntu/Linaro 4.6.3-1ubuntu3) 4.6.3
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

РЕДАКТИРОВАТЬ:

Использование const (как при создании foo с указателем const и пометке value() как const) дает ту же ошибку.


person elcuco    schedule 01.04.2012    source источник
comment
@jalf см. ответ Мэта, чтобы понять. В моем случае переменная находится в области видимости при вызове функции.   -  person elcuco    schedule 01.04.2012
comment
Нельзя ли изменить подпись функции на int foo(const Integer& i);?   -  person jrok    schedule 01.04.2012


Ответы (3)


Integer i(12);
foo(&i);

Это избавляет от проблемы «взять адрес временного», которая у вас есть. Вы не передаете адрес локальной переменной (что делает вышеприведенное, и в этом случае это действительно нормально), вы захватываете адрес временного.

Очевидно, что если foo так или иначе попытается удержать этот указатель, у вас возникнут проблемы в будущем.

person Mat    schedule 01.04.2012
comment
вы захватываете адрес временного объекта, что очень подозрительно. Нет, это не подозрительно. Поведение четко определено,12.2/3 Временные объекты уничтожаются в качестве последнего шага в оценке полного -выражение, которое (лексически) содержит точку, где они были созданы. - person Alok Save; 01.04.2012
comment
Это не более опасно, чем ссылка на rvalue. - person Puppy; 01.04.2012
comment
Хорошо, я не имел в виду, что это было недействительно, просто (IMO) подозрительно. - person Mat; 01.04.2012
comment
@Mat, мне нужно, чтобы это был один вкладыш без временных переменных, так как это временная переменная, сгенерированная макросом DEBUG (в моем приложении это структура, которая содержит информацию о строке, файле, времени, идентификаторе потока и т. д.). - person elcuco; 01.04.2012
comment
@elcuco: { Integer i(12); foo(&i); } - person Mat; 01.04.2012
comment
@elcuco: мой ответ уже содержит это. {} не добавляет ничего реального. - person Mat; 01.04.2012
comment
@Mat Ценность в том, что это дает понять, что на высоком уровне это подразумевается как одна операция и разбивается на две только по техническим причинам, и это ограничивает область действия однобуквенной i var, которая может быть считается табу стандарта кодирования, если не используется в строго ограниченных рамках. - person Slipp D. Thompson; 31.12.2014

template<typename T> const T* rvalue_address(const T& in) {
    return &in;
}

На мой взгляд, const T* должно быть столь же законным, как и const T&, но эта тривиальная функция легко выполнит преобразование.

person Puppy    schedule 01.04.2012

GCC ошибается в этом случае. Ваше целое число является значением r, и использование адреса значения r является незаконным.

§5.3.1 Унарные операторы, раздел 3

Результатом унарного оператора & является указатель на его операнд. Операнд должен быть lvalue или квалифицированным идентификатором.

Clang выдает ошибку в этом случае:

error: taking the address of a temporary object of type 'Integer' [-Waddress-of-temporary]
    foo( &Integer(12) );
         ^~~~~~~~~~~~
person Nikola Smiljanić    schedule 01.04.2012
comment
GCC не ошибся, он отклонил его с error:, потому что это незаконно. -fpermissive — это расширение GCC, которое, по сути, говорит да, хорошо, я понимаю, что вы имеете в виду. Расширениям разрешено делать любые нестандартные вещи, потому что они нестандартные расширения. - person ams; 02.04.2012
comment
Стандарт требует диагностики для любой неправильно сформированной программы, если не указано иное. Предупреждение — это диагностика. Даже если GCC выдаст просто предупреждение без -fpermissive, это не будет проблемой соответствия. - person Arne Vogel; 08.07.2015