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

时间:2014-05-15 17:57:16

标签: c++ visual-studio-2012 c++11 language-lawyer

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

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有错误而且我还没有找到标准的相关部分?

3 个答案:

答案 0 :(得分: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

不允许将右值与非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]

引用语句的后半部分允许将临时值绑定到右值引用,如litb's answer所示。

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

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

答案 1 :(得分:12)

本节中从未出现const这个词。规则 一直以来(只要我记得) 临时用于初始化引用有其生命周期 扩展以匹配引用的引用,无论类型如何 参考。

在1980年代后期的某个时间(非常标准化),C ++推出 暂时不能用于初始化的规则 非const引用。使用初始化非const引用 一个临时的仍会延长寿命(大概),但是 因为你无法做到......大多数编译器都已实现 过渡期,只有这样的初始化 发出警告(延长寿命)。

出于某种原因,当微软最终决定实施时 C ++(1990年代早期的某个时候),他们决定不这样做 实现新规则,并允许初始化 带有临时的非const引用(甚至没有警告, 在大多数其他供应商逐渐转向的时候 警告错误)。当然,实施了 通常的终身规则。

最后,在C ++ 11中,引入了新类型的引用, 允许(甚至需要)初始化 暂时的。关于临时生命的规则还没有 但是改变了;用于初始化的临时用例 参考(不论参考类型)有它的 终生延长。

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

答案 2 :(得分:5)

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

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

寿命仍在扩大。使代码对非const左值引用无效的约束在第8节(请注意,在引用的段落中添加“const”和“rvalue reference”等不是正确的位置。您需要这种绑定的主动拒绝,而不仅仅是说这种绑定的生命周期没有扩大,因为你会让绑定本身保持良好状态)。