const引用是否延长了临时的生命?
为什么这样做:
#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; }
给出输出:
答案是:
代替:
答案是:四
只有本地 const
引用延长寿命。
该标准在§8.5.3/ 5 [dcl.init.ref]中指定了这种行为,即引用声明的初始值设定部分。 你的例子中的引用绑定到构造函数的参数n
,并且当对象n
被绑定到超出作用域时变为无效。
生命周期延长不是通过函数parameter passing的。 §12.2/ 5 [class.temporary]:
第二个上下文是引用绑定到临时的时候。 引用所绑定的临时对象或临时绑定到的子对象的完整对象的临时对象在引用的生存期内保留,除非如下所述。 在构造函数的ctor-initializer(§12.6.2[class.base.init])中临时绑定到引用成员,直到构造函数退出。 临时绑定到函数调用(§5.2.2[expr.call])中的引用参数,直到完成包含调用的完整expression式。
以下是解释发生的最简单的方法:
在main()中,您创build了一个string并将其传递给构造函数。 这个string实例只存在于构造函数中。 在构造函数中,您指定了成员直接指向此实例。 当范围离开构造函数时,string实例被销毁,然后成员指向一个不再存在的string对象。 让Sandbox.member指向其作用域之外的引用不会将这些外部实例保留在范围之内。
如果您想修复程序以显示您所需的行为,请进行以下更改:
int main() { string temp = string("four"); Sandbox sandbox(temp); cout << sandbox.member << endl; return 0; }
现在temp会在main()的末尾而不是在构造函数的结尾处超出范围。 但是,这是不好的做法。 您的成员variables不应该是对实例外部存在的variables的引用。 在实践中,你永远不知道这个variables何时会超出范围。
我build议将Sandbox.member定义为一个const string member;
这会将临时参数的数据复制到成员variables中,而不是将成员variables指定为临时参数本身。
从技术上讲,这个程序并不需要输出任何东西到标准输出(这是一个缓冲stream)。
-
cout << "The answer is: "
位将发出"The answer is: "
到stdout的缓冲区中。 -
然后,
<< sandbox.member
位将向operator << (ostream &, const std::string &)
提供悬挂引用,该引用调用未定义的行为 。
正因为如此,没有保证会发生。 该程序可能看起来很好,甚至可能崩溃甚至没有冲洗标准输出 – 这意味着文本“答案是:”不会出现在你的屏幕上。
因为一旦Sandbox构造函数返回,您的临时string超出了范围,并且为了其他目的而回收了它所占用的堆栈。
一般来说,你不应该长期保留参考。 引用对于参数或局部variables是好的,从来没有类成员。