C++ const引用类成员是否延长了临时类的寿命?
为什么会这样:C++ const引用类成员是否延长了临时类的寿命?,c++,temporary,ctor-initializer,const-reference,C++,Temporary,Ctor Initializer,Const Reference,为什么会这样: #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 <&
#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;
}
#包括
#包括
使用名称空间std;
类沙箱
{
公众:
沙盒(conststring&n):成员(n){}
常量字符串和成员;
};
int main()
{
沙箱沙箱(串(“四”));
不能只有局部const
引用可以延长寿命
本标准在§8.5.3/5、[dcl.init.ref]中规定了此类行为,这是关于引用声明的初始值设定项的一节。示例中的引用绑定到构造函数的参数n
,当对象n
绑定到超出范围时,该引用将无效
生存期扩展不能通过函数参数传递。§12.2/5[类.临时]:
第二个上下文是引用绑定到临时对象时的上下文。该引用绑定到的临时对象或该临时对象绑定到的子对象的完整对象的临时对象在引用的生命周期内持续存在,以下指定的情况除外。临时绑定到构造函数中的引用成员zer(§12.6.2[class.base.init])持续存在,直到构造函数退出。函数调用(§5.2.2[expr.call])中引用参数的临时绑定持续存在,直到包含调用的完整表达式完成
因为一旦沙盒构造函数返回,您的临时字符串就超出了范围,并且它占用的堆栈被回收用于其他目的
通常,您不应长期保留引用。引用适用于参数或局部变量,而不适用于类成员。以下是解释所发生情况的最简单方法:
大体上您创建了一个字符串并将其传递到构造函数中。此字符串实例仅存在于构造函数中。在构造函数中,您指定成员直接指向此实例。当作用域离开构造函数时,字符串实例被销毁,然后成员指向不再存在的字符串对象。使用Sandbox、 指向其作用域之外引用的成员点将不会在作用域中保留这些外部实例
如果要修复程序以显示所需的行为,请进行以下更改:
int main()
{
string temp = string("four");
Sandbox sandbox(temp);
cout << sandbox.member << endl;
return 0;
}
intmain()
{
字符串温度=字符串(“四”);
沙箱(温度);
cout从技术上讲,这个程序实际上不需要将任何内容输出到标准输出(首先是一个缓冲流)
cout你指的是某个已经消失的东西
#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;
}
#包括
#包括
类沙箱
{
公众:
const string member=“;//默认为任何要求
沙盒(conststring&n):成员(n){}//创建了一个副本
};
int main()
{
沙箱沙箱(串(“四”));
std::cout从其他答案可以清楚地看出,类成员不会在构造函数调用之外延长临时对象的生命。不过,在某些情况下,您的API可以“安全”地假设传递给类的所有常量和对象都不是临时对象,而是对范围良好的对象的引用
如果您不想创建副本,您可以做些什么来确保UB不会潜入您的代码中?您拥有的最佳工具是通过声明接受此类临时变量的重载为已删除,来维护传递给构造函数的std::string const&
不是临时变量的假设:
#包括
#包括
使用名称空间std;
类沙箱
{
公众:
沙盒(conststring&n):成员(n){}
沙盒(字符串&&)=删除;
//^^^^这个家伙;)
常量字符串和成员;
};
int main()
{
沙箱沙箱(串(“四”));
//检测到您正试图^^^^绑定
//引用临时文件并拒绝编译
返回0;
}
“永远不会”是一个非常强的词。除非需要保留对某个对象的引用,否则不要使用类成员。在某些情况下,需要保留对其他对象的引用,而不是副本,因为这些情况下,引用比指针更清晰。您还应该参阅GotW#88以获得更人性化的解释:我认为如果tandard说“第二种情况是引用绑定到prvalue”。在OP的代码中,您可以说成员
绑定到一个临时对象,因为用n
初始化成员
意味着将成员
绑定到同一个对象n
绑定到,在这种情况下,这实际上是一个临时对象。@M.M在某些情况下,左值或x值初始值设定项包含prvalue将扩展prvalue。我的提案文件回顾了现状。从C++11开始,右值引用还可以延长临时值的寿命,而不需要const
qualifier。@KeNVinFavo是的,使用死对象总是UBA,只是为了更有趣,如果你写过cout@RogerPate,你能解释为什么吗?对于居里的人来说例如,罗杰·佩特(Roger Pate)因为字符串(“四”)而发表作品是临时的,并且该临时性在完全扩展结束时被销毁,因此在他的示例中,当读取SandBox::member
时,临时字符串仍然是活动的。问题是:既然编写此类类是危险的,那么是否有编译器警告不要将临时性传递给此类,或者是否有设计准则(在Stroustroup中?)这禁止编写存储引用的类?一个存储指针而不是引用的设计指南会更好。FWIW,我无法在GCC或MSVC 2013上重现“答案是:”的输出。这通常需要-O3或其他东西来显示自己吗?如果我这样做:const string&temp=string(“四”);Sandbox Sandbox(temp);cout@Thomasconst string&temp=string(“四”);
给出与const string temp(“四”);
相同的结果,除非您使用decltype(temp)
specifically@M.M非常感谢现在我知道了