非const引用是否会延长临时对象的寿命?

Do *non*-const references prolong the lives of temporaries?

本文关键字:临时对象 const 引用 是否      更新时间:2023-10-16

以前,我认为这样的代码会失败:

const MyClass& obj = MyClass();
obj.DoSomething();

,因为MyClass对象将在其完整表达式结束时被销毁,使obj成为悬空引用。然而,我(在这里)了解到这不是真的;该标准实际上有一个特殊的规定,允许const引用保持临时存在,直到所述引用自己被销毁。但是,需要强调的是,只有const引用具有这种功能。今天我在VS2012中运行了下面的代码作为实验。

struct Foo
{
    Foo() { std::cout << "ctor" << std::endl; }
    ~Foo() { std::cout << "dtor" << std::endl; }
};
void f()
{
    Foo& f = Foo();
    std::cout << "Hello world" << std::endl;
}

调用f()时的输出为:

ctor  
Hello world  
dtor  

所以我看了看c++ 11标准草案,只发现了这个(§12.2/4):

有两种上下文中,临时值在a处被销毁不同的点比结束的充分表达。第一个上下文没有应用)。第二个上下文是当引用绑定到暂时的。对象绑定到的临时对象对象所指向的子对象的完整对象引用被绑定,在引用的生命周期内持续存在。

上面明显没有const这个词。所以;这种行为是否已更改为c++ 11,我错了关于const的事情开始,或者VS2012有一个错误,我只是没有找到标准的相关部分?

行为没有改变,您只需要将警告级别提高到/W4。VisualStudio甚至将非const左值引用作为编译器扩展来实现生存期扩展规则。在这种情况下,将右值绑定到非const引用的行为与将其绑定到const引用的行为相同。

使用/W4,你会看到这样:

warning C4239: nonstandard extension used : 'initializing' : conversion from 'Foo' to 'Foo &'
1>  A non-const reference may only be bound to an lvalue

禁止将右值绑定到非const左值引用的文本可以在§8.5.3/5

中找到。

本;否则,该引用应为对非易失性const类型的左值引用(即cv1应为)const),否则引用必须是右值引用。
(例子:

  double& rd2 = 2.0; // error: not an lvalue and reference not const
  int i = 2;
  double& rd3 = i; // error: type mismatch and reference not const

-end example]

引用语句的后半部分允许将临时值绑定到右值引用,如lib的答案所示。

string &&s = string("hello");

这与§12.2/5中的生存期扩展规则相结合,意味着临时对象的生存期现在将匹配它所绑定的(rvalue)引用的生存期。

本节中从未出现过const这个词。规则一直是(从我记事起)用于初始化引用的临时变量有其生存期扩展以匹配引用的类型,而不考虑类型参考文献。

在20世纪80年代末的某个时候(非常标准之前),c++被引入不能使用临时对象初始化的规则非const引用。初始化非const引用临时的仍然会延长生命周期(大概),但是既然你做不到……大多数编译器实现一个过渡时期,在此期间,这样的初始化只会发出警告(并延长生存期)。

由于某种原因,当微软最终决定实现c++(在20世纪90年代早期),他们决定不这么做实现新规则,并允许初始化带有临时(甚至没有警告)的非const引用,在大多数其他供应商逐渐转向的时候警告为错误)。当然,它实现了通常的生命周期规则。

最后,在c++ 11中引入了新的引用类型,哪个允许(甚至需要)初始化一个临时的。关于临时工寿命的规则没有改变,虽然;一个用于初始化的临时对象一个引用(不管引用的类型是什么)都有它的寿命延长。

(有几个例外:我不建议使用临时的在初始化中初始化类成员引用列表。)

不,因为右值引用不需要是const,所以标准引号是正确的

string &&s = string("hello");

寿命仍然增大。使代码对非const左值引用无效的约束是在第8条(请注意,这不是在您引用的段落中添加"const"answers"右值引用"等的正确位置。您需要主动拒绝这些绑定,而不仅仅是说这些绑定的生命周期没有延长,因为您将使绑定本身保持良好形式)。