Bezdepbonusu7Программирование: статьи и ответы

Вопрос

C++: постоянная ссылка на временный

Автор вопроса: peoroОтветов: 5

Есть несколько вопросов о времени жизни постоянной ссылки на 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 не обнаруживает никаких ошибок во время выполнения.

Что мне не хватает в ссылках?

  • Когда вы передаете ссылку конструктору объекта, который принимает ссылку, вы потенциально передаете ссылку на время жизни созданного объекта. В таком случае ваша обязанность убедиться, что объект, на который ссылаются, живет дольше, чем вновь созданный объект. Martin York 24.12.2010

c++referenceconstantslifetimetemporary

Ответы

Ответ 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;
}

Я думаю, что правило для ссылок на временное работает только для локальных переменных, а не для членов.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы