C++ const 引用类成员是否会延长临时对象的生命周期?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2784262/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 00:39:32  来源:igfitidea点击:

Does a const reference class member prolong the life of a temporary?

c++temporaryctor-initializerconst-reference

提问by Kyle

Why does this:

为什么会这样:

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

Give output of:

给出以下输出:

The answer is:

答案是:

Instead of:

代替:

The answer is: four

答案是:四

采纳答案by Potatoswatter

Only localconstreferences prolong the lifespan.

只有本地const引用才能延长生命周期。

The standard specifies such behavior in §8.5.3/5, [dcl.init.ref], the section on initializers of reference declarations. The reference in your example is bound to the constructor's argument n, and becomes invalid when the object nis bound to goes out of scope.

该标准在第 8.5.3/5 节 [dcl.init.ref] 中指定了此类行为,该部分关于引用声明的初始化程序。您示例中的引用绑定到构造函数的参数n,并且当对象n绑定到超出范围时将变为无效。

The lifetime extension is not transitive through a function argument. §12.2/5 [class.temporary]:

生命周期扩展不能通过函数参数传递。§12.2/5 [class.temporary]:

The second context is when a reference is bound to a temporary. The temporary to which the reference is bound or the temporary that is the complete object to a subobject of which the temporary is bound persists for the lifetime of the reference except as specified below. A temporary bound to a reference member in a constructor's ctor-initializer (§12.6.2 [class.base.init]) persists until the constructor exits. A temporary bound to a reference parameter in a function call (§5.2.2 [expr.call]) persists until the completion of the full expression containing the call.

第二个上下文是引用绑定到临时对象时。引用绑定到的临时对象或作为临时对象绑定到的子对象的完整对象的临时对象在引用的生命周期内持续存在,除非在下面指定。临时绑定到构造函数的 ctor-initializer (§12.6.2 [class.base.init]) 中的引用成员会一直存在,直到构造函数退出。函数调用(第 5.2.2 节 [expr.call])中引用参数的临时绑定一直存在,直到包含调用的完整表达式完成。

回答by Squirrelsama

Here's the simplest way to explain what happened:

这是解释发生了什么的最简单方法:

In main() you created a string and passed it into the constructor. This string instance only existed within the constructor. Inside the constructor, you assigned member to point directly to this instance. When when scope left the constructor, the string instance was destroyed, and member then pointed to a string object that no longer existed. Having Sandbox.member point to a reference outside its scope will not hold those external instances in scope.

在 main() 中,您创建了一个字符串并将其传递给构造函数。这个字符串实例只存在于构造函数中。在构造函数中,您分配了成员以直接指向此实例。当作用域离开构造函数时,字符串实例被销毁,然后成员指向一个不再存在的字符串对象。让 Sandbox.member 指向其范围之外的引用不会将这些外部实例保留在范围内。

If you want to fix your program to display the behavior you desire, make the following changes:

如果您想修复您的程序以显示您想要的行为,请进行以下更改:

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

Now temp will pass out of scope at the end of main() instead of at the end of the constructor. However, this is bad practice. Your member variable should never be a reference to a variable that exists outside of the instance. In practice, you never know when that variable will go out of scope.

现在 temp 将在 main() 结束而不是在构造函数结束时超出范围。然而,这是不好的做法。您的成员变量永远不应该是对存在于实例之外的变量的引用。实际上,您永远不知道该变量何时会超出范围。

What I recommend is to define Sandbox.member as a const string member;This will copy the temporary parameter's data into the member variable instead of assigning the member variable as the temporary parameter itself.

我推荐的是将 Sandbox.member 定义为 aconst string member;这会将临时参数的数据复制到成员变量中,而不是将成员变量分配为临时参数本身。

回答by Tanz87

Technically speaking, this program isn't required to actually output anything to standard output (which is a buffered stream to begin with).

从技术上讲,这个程序不需要实际输出任何东西到标准输出(这是一个缓冲流)。

  • The cout << "The answer is: "bit will emit "The answer is: "into the bufferof stdout.

  • Then the << sandbox.memberbit will supply the dangling reference into operator << (ostream &, const std::string &), which invokes undefined behavior.

  • cout << "The answer is: "位将发送"The answer is: "到stdout的缓冲区中。

  • 然后该<< sandbox.member位将提供悬空引用到 中operator << (ostream &, const std::string &),这会调用未定义的行为

Because of this, nothing is guaranteed to happen. The program may work seemingly fine or may crash without even flushing stdout -- meaning the text "The answer is: " would not get to appear on your screen.

正因为如此,什么都不能保证发生。该程序可能看起来运行良好,或者可能在没有刷新标准输出的情况下崩溃——这意味着文本“答案是:”不会出现在您的屏幕上。

回答by pcodex

you're referring to something which has vanished. The following will work

你指的是已经消失的东西。以下将起作用

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

回答by Fyodor Soikin

Because your temporary string went out of scope once the Sandbox constructor returned, and the stack occupied by it was reclaimed for some other purposes.

因为一旦 Sandbox 构造函数返回,您的临时字符串就超出了范围,并且它占用的堆栈被回收用于其他目的。

Generally, you should never retain references long-term. References are good for arguments or local variables, never class members.

通常,您永远不应该长期保留引用。引用适用于参数或局部变量,而不是类成员。