Есть несколько вопросов о времени жизни постоянной ссылки на SO, но я все равно не понимаю.
Этот кусок кода действителен?
struct S
{
const int &ref;
S( const int &x ) : ref(x) { }
};
int main( )
{
S s( 0 );
// ...
use( s.ref );
// ...
return 0;
}
Интуитивно я бы сказал нет, так как 0 должен истечь после того, как выражение (S s(0);) будет оценено.
Однако и GCC, и CLANG компилируют его нормально, без предупреждений, и valgrind не обнаруживает никаких ошибок во время выполнения.
Что мне не хватает в ссылках?
Ответ 1 · рейтинг 4 · icecrime
Мне кажется недействительным в соответствии с 12.2/4:
Есть два контекста, в которых временные объекты уничтожаются не в конце полного выражения. Первый контекст - когда выражение появляется как инициализатор для декларатора, определяющего объект. В этом контексте временное значение, содержащее результат выражения, должно сохраняться до завершения инициализации объекта.
Временный объект будет жить только до тех пор, пока s не будет полностью построен, а не до момента вызова use.
Ответ 2 · рейтинг 2 · doron
Как указывают другие, стандарт С++ заставляет компилятор сохранять временное значение 0 только на время вызова конструктора. На практике gcc сохраняет временное значение на время работы функции main, что приводит к тому, что программа работает, как и ожидалось. По этой причине нет никаких предупреждений или ошибок во время выполнения.
Но это работает только случайно. Не полагайтесь на это поведение.
Ответ 3 · рейтинг 1 · wilhelmtell
Здесь следует отметить не const, а ссылку. Константа - это просто инструмент для статического анализа. Вы должны быть осторожны со ссылками, потому что они могут кусаться.
int& f()
{
int i = 2;
return i;
}
Иногда компилятор достаточно умен, чтобы предупредить вас о проблемах, которые могут возникнуть во время выполнения, но иногда это не так. В любом случае компилятор не должен предупреждать вас об этом.
Ответ 4 · рейтинг 1 · Jester
Вот еще одна настройка вашего кода, на которую жалуется даже valgrind:
#include <iostream>
struct S
{
const int &ref;
S( const int &x ) : ref(x) { }
};
S* foo()
{
return new S(0);
}
int main( )
{
S* s = foo();
std::cout << s->ref << std::endl;
return 0;
}
Обычно это помещает временное значение во фрейм стека функции foo, поэтому оно уничтожается, когда эта функция возвращается. Это похоже на возврат адреса локальной переменной.
В других ответах указано, почему компилятору разрешено это делать, мой код - просто иллюстрация.
Ответ 5 · Mark Ransom
0 не временное, это буквальное. Попробуйте это небольшое изменение в вашей программе:
struct S
{
const int &ref;
S( const int &x ) : ref(x) { }
};
int f()
{
return 0;
}
int main( )
{
S s( f() );
// ...
use( s.ref );
// ...
return 0;
}
Я думаю, что правило для ссылок на временное работает только для локальных переменных, а не для членов.