Почему делает это:
#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;
}
Дайте вывод:
Ответ:
Вместо:
Ответ: четыре
. Только ссылки local const
продлевают срок службы.
Стандарт определяет такое поведение в §8.5.3/5, [dcl.init.ref], раздел об инициализаторах объявлений ссылок. Ссылка в вашем примере привязана к аргументу конструктора n
и становится недействительной, когда привязанный объект n
выходит за пределы области видимости.
Увеличение срока службы не является транзитивным через аргумент функции. §12.2 / 5 [class.porary]:
Второй контекст - это когда ссылка привязана к временному объекту. Временный объект, к которому привязана ссылка, или временный объект, являющийся полным объектом для подобъекта, к которому привязан временный объект, сохраняется в течение всего времени существования ссылки, за исключением случаев, указанных ниже. Временная привязка к ссылочному элементу в ctor-initializer конструктора (§12.6.2 [class.base.init]) сохраняется до выхода из конструктора. Временная привязка к параметру ссылки в вызове функции (§5.2.2 [expr.call]) сохраняется до завершения полного выражения, содержащего вызов.
Вот самый простой способ объяснить, что произошло:
In main () вы создали строку и передали ее конструктору. Этот экземпляр строки существовал только в конструкторе. Внутри конструктора вы назначили член, указывающий непосредственно на этот экземпляр. Когда область видимости покинула конструктор, экземпляр строки был уничтожен, а член затем указал на строковый объект, который больше не существовал. Если Sandbox.member указывает на ссылку за пределами его области видимости, эти внешние экземпляры не будут находиться в области видимости.
Если вы хотите исправить свою программу, чтобы она отображала желаемое поведение, внесите следующие изменения:
int main()
{
string temp = string("four");
Sandbox sandbox(temp);
cout << sandbox.member << endl;
return 0;
}
Теперь temp выйдет за пределы области видимости в конце main (), а не в конце конструктора. Однако это плохая практика. Ваша переменная-член никогда не должна быть ссылкой на переменную, существующую вне экземпляра. На практике вы никогда не знаете, когда эта переменная выйдет за пределы области видимости.
Я рекомендую определить Sandbox.member как константный строковый член ;
Это скопирует данные временного параметра в переменную-член, вместо того, чтобы назначать переменную-член как сам временный параметр.
Потому что ваша временная строка вышла из области видимости после возвращения конструктора Sandbox, и стек, занятый ею, был возвращен для других целей.
Вообще, вы никогда не должны сохранять ссылки надолго. Ссылки хороши для аргументов или локальных переменных, но никак не для членов класса.