Продлевает ли член класса Const Reference временный срок? - PullRequest
154 голосов
/ 07 мая 2010

Почему это:

#include <string>
#include <iostream>
using namespace std;

class Sandbox
{
public:
    Sandbox(const string& n) : member(n) {}
    const string& member;
};

int main()
{
    Sandbox sandbox(string("four"));
    cout << "The answer is: " << sandbox.member << endl;
    return 0;
}

Дайте вывод:

Ответ:

Вместо:

Ответ: четыре

Ответы [ 5 ]

153 голосов
/ 07 мая 2010

Только локальные const ссылки продлевают срок службы.

Стандарт определяет такое поведение в §8.5.3 / 5, [dcl.init.ref], раздел об инициализаторахсправочных объявлений.Ссылка в вашем примере связана с аргументом конструктора n и становится недействительной, когда объект n выходит из области видимости.

Расширение времени жизни не транзитивно через аргумент функции.§12.2 / 5 [class.teven]:

Второй контекст - это когда ссылка связана с временным.Временный объект, к которому привязана ссылка, или временный объект, являющийся полным объектом для подобъекта, к которому привязан временный объект, сохраняется в течение всего срока действия ссылки, за исключением случаев, указанных ниже.Временная привязка к элементу ссылки в ctor-initializer конструктора (§12.6.2 [class.base.init]) сохраняется до выхода из конструктора.Временная привязка к ссылочному параметру в вызове функции (§5.2.2 [expr.call]) сохраняется до завершения полного выражения, содержащего вызов.

23 голосов
/ 07 мая 2010

Вот самый простой способ объяснить, что произошло:

В main () вы создали строку и передали ее в конструктор. Этот экземпляр строки существовал только внутри конструктора. Внутри конструктора вы назначили член, чтобы указывать непосредственно на этот экземпляр. Когда область видимости покинула конструктор, экземпляр строки был уничтожен, а член указал на строковый объект, которого больше не существовало. Если указатель Sandbox.member на ссылку за пределами области его действия, эти внешние экземпляры не будут удерживаться в области.

Если вы хотите исправить свою программу для отображения желаемого поведения, внесите следующие изменения:

int main()
{
    string temp = string("four");    
    Sandbox sandbox(temp);
    cout << sandbox.member << endl;
    return 0;
}

Теперь temp будет выходить из области видимости в конце main (), а не в конце конструктора. Однако это плохая практика. Ваша переменная-член никогда не должна быть ссылкой на переменную, которая существует вне экземпляра. На практике вы никогда не знаете, когда эта переменная выйдет из области видимости.

Я рекомендую определить Sandbox.member как const string member; Это позволит скопировать данные временного параметра в переменную-член вместо назначения переменной-члена в качестве самого временного параметра.

4 голосов
/ 09 мая 2015

Технически говоря, эта программа не обязана выводить что-либо на стандартный вывод (для начала это буферизованный поток).

  • Бит cout << "The answer is: " будет выдавать "The answer is: " в буфер стандартного вывода.

  • Затем бит << sandbox.member подаст висячую ссылку в operator << (ostream &, const std::string &), что вызывает неопределенное поведение .

Из-за этого ничего не гарантируется. Программа может работать на вид нормально или может зависнуть даже без очистки стандартного вывода - это означает, что текст «Ответ:» не появится на вашем экране.

0 голосов
/ 09 марта 2018

простой ответ: вы имеете в виду что-то, что исчезло.Следующее будет работать

#include <string>
#include <iostream>
using namespace std;

class Sandbox
{

public:
    const string member = " ";
    Sandbox(const string& n) : member(n) {}//a copy is made

};

int main()
{
    Sandbox sandbox(string("four"));
    cout << "The answer is: " << sandbox.member << endl;
    return 0;
}
0 голосов
/ 07 мая 2010

Поскольку ваша временная строка вышла из области видимости после возвращения конструктора Sandbox и занятый ею стек был возвращен для некоторых других целей.

Как правило, вы никогда не должны сохранять ссылки на длительный срок. Ссылки хороши для аргументов или локальных переменных, но не для членов класса.

...