什么决定了临时工的生命周期何时扩展到const引用或rvalue引用?

时间:2015-08-03 20:50:08

标签: c++ c++11 reference rvalue-reference lifetime

假设:

struct hurg { ... };

hurg get_hurg() { return hurg(); }
hurg&& get_mhurg() { return hurg(); }

我的理解and experimenting表明以下是未定义的行为(编辑:感谢答案,结果我错了,get_mhurg()示例未定义的行为):

{
    const hurg& a = get_hurg(); 
    hurg&& b = get_hurg();
    const hurg& c = get_mhurg(); 
    hurg&& d = get_mhurg();
    // do stuff with a, b, c, d
}
// a, b, c, d are now destructed

也就是说,hurgget_hurg()返回的临时get_mhurg()对象的生命周期一直延长到范围结束。

但是,对于(here}的函数):

template <typename T>
auto id(T&& x) -> decltype(auto) { return decltype(x)(x); }    

使用它像:

{
    const hurg& x = id(hurg()); 
    // the hurg() 'x' refers to is already destructed

    hurg&& y = id(hurg());
    // the hurg() 'y' refers to is already destructed

    // undefined behavior: use 'x' and 'y'
}

在这种情况下,hurg的生命周期扩展。

一般来说,什么时候延长临时生命的时间?并且,特别是,何时将函数的结果绑定到const lvalue ref或rvalue ref是安全的?

更具体地说,id案件究竟发生了什么?

2 个答案:

答案 0 :(得分:6)

来自[class.temporary]:

  

有两种情况下,临时表在不同于完整表达结束时被摧毁。   第一个上下文是调用默认构造函数来初始化数组的元素[...]

     

第二个上下文是引用绑定到临时的。引用所在的临时值   绑定或临时是绑定引用的子对象的完整对象   在参考文件的生命周期中除外:
  (5.1) - 绑定到函数调用(5.2.2)中的引用参数的临时对象一直持续到完成   包含该呼叫的完整表达式   (5.2) - 函数返回语句(6.6.3)中返回值的临时绑定的生存期不是   扩展;临时在return语句中 full-expression 的末尾被销毁   (5.3) - new-initializer (5.3.4)中引用的临时绑定一直持续到完成   包含 new-initializer 完整表达式

所以有两件事。首先,get_mhurg是未定义的行为。您返回的临时生命周期延长。其次,传递到id的临时值持续到包含函数调用的完整表达式结束,但没有进一步的。与get_mhurg一样,临时不是通过扩展。所以这也是未定义的行为。

答案 1 :(得分:4)

  

我的理解和实验表明,以下情况并非如此   未定义的行为:

嗯,你的理解和实验是错误的。明智的提示 - 不要尝试未定义的行为。例如,您的实验可能会随机发生,表明它是明确定义的行为,这是未定义行为的可能结果之一。

使用get_mhurg()的返回值是未定义的行为。您正在访问创建它的范围之外的临时hurg()

id情况只是表明终生延期是他妈的蠢。

具体而言,终身扩展仅直接适用于。它从不适用于任何类型的引用。您必须使用值初始化引用。 id不返回值,因此不会应用生命周期扩展。