Является ли член-ссылочный класс константы продлением срока службы временного?

Почему это:

#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;
}

Выдать результат:

Ответ:

Вместо:

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

Ответ 1

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

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

Расширение продолжительности жизни не является транзитивным с помощью аргумента функции. §12.2/5 [class.temporary]:

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

Ответ 2

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

В 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;. Это скопирует временные данные параметров в переменную-член вместо назначения переменной-члена как самого временного параметра.

Ответ 3

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

  • Бит cout << "The answer is: " испускает "The answer is: " в буфер stdout.

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

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

Ответ 4

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

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

Ответ 5

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

#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;
}

Ответ 6

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

#include <string>
#include <iostream>

class Sandbox
{

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

};

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