***const参考是否延长了临时生命?

dlf*_*dlf 16 c++ language-lawyer c++11 visual-studio-2012

曾几何时,我认为像这样的代码会失败:

const MyClass& obj = MyClass();
obj.DoSomething();
Run Code Online (Sandbox Code Playgroud)

因为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;
}
Run Code Online (Sandbox Code Playgroud)

调用时的输出f()是:

ctor  
Hello world  
dtor  
Run Code Online (Sandbox Code Playgroud)

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

有两种情况,临时表在与完整表达结束时不同的地方被摧毁.第一个背景[不适用].第二个上下文是引用绑定到临时的.绑定引用的临时对象或绑定引用的子对象的完整对象的临时对象在引用的生命周期内持续存在.

const上面显然没有这个词.所以; 有没有为C++ 11改变这种行为,我const开始的事情是错的,还是VS2012有一个bug,我还没有找到标准的相关部分?

Pra*_*ian 14

行为没有改变,你只需要将你的警告级别提高到/W4.即使非const左值引用作为编译器扩展,VisualStudio也实现了生命周期扩展规则.在此上下文中,将rvalue绑定到非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
Run Code Online (Sandbox Code Playgroud)

不允许将右值与非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
Run Code Online (Sandbox Code Playgroud)

- 末端的例子]

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

string &&s = string("hello");
Run Code Online (Sandbox Code Playgroud)

这与§12.2/ 5中的生命周期扩展规则相结合,意味着临时的生命周期现在将与其绑定的(rvalue)引用的生命周期相匹配.

  • @dlf从来没有"只有const引用延长生命周期"的规则.早在规则禁止使用临时初始化非const引用之前,生命周期的扩展应用于所有引用. (3认同)
  • 允许将rvalue绑定到非const左值引用的事实本身就是一个扩展. (2认同)
  • @Brian是不是我说的? (2认同)

Jam*_*nze 12

这个词const从未出现在本节中.规则一直是(从我记忆中),无论引用的类型如何,用于初始化引用的临时对象的生命周期都会扩展到与引用的生命周期相匹配.

在1980年代后期的某个时候(非常标准化),C++引入了一个规则,即临时不能用于初始化非const引用.使用临时函数初始化非const引用仍然可以延长生命周期(大概),但是因为你不能这样做...大多数编译器实现了一个过渡期,其中这样的初始化只会发出警告(和生命周期)被延长了).

出于某种原因,当微软最终决定实施C++时(在1990年代早期的某个时候),他们决定不实施新规则,并允许使用临时(甚至没有警告,一次)初始化非const引用当大多数其他供应商逐渐将警告转变为错误时).当然,实施了通常的生命周期规则.

最后,在C++ 11中,引入了新类型的引用,它允许(甚至需要)使用临时初始化.然而,关于临时生命的规则没有改变; 用于初始化引用的临时(无论引用的类型如何)都会延长其生命周期.

(除了少数例外:我不建议使用临时初始化初始化列表中的类成员引用.)

  • @ChristianHackl用于初始化成员引用的临时用户的生命周期_not_扩展到引用的生命周期; 它的生命周期结束于构造函数的末尾(导致悬空引用). (2认同)

Joh*_*itb 5

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

string &&s = string("hello");
Run Code Online (Sandbox Code Playgroud)

寿命仍在扩大.使对非const左值参考代码无效约束是在第8(注意它是不是只是添加"常量",并在你引用了一段"右值引用"等正确的地方.你需要一个积极的拒绝的这样的绑定,不仅仅是说这种绑定的生命周期没有扩大,因为你会让绑定本身保持良好状态).