Взима се временен адрес - необходимо е решение

Изправен съм пред предупреждение от 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 да вземе константен указател и маркирането на 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 (в моето приложение това е структура, която поддържа информация за ред, файл, време, threadID и т.н.). - 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 греши в този случай. Вашето цяло число е rvalue и вземането на адреса на rvalue е незаконно.

§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