xvalue的生命周期是否会因为引用被延长而延长?

6

显然在编译器之间存在一些混淆和差异,涉及到这个问题:

http://social.msdn.microsoft.com/Forums/vstudio/en-US/3c754c4e-5471-4095-afae-795c1f411612/rvalue-refs-extended-lifetime-inconsistent-with-gccstandard

根据这篇文章: 什么是rvalues、lvalues、xvalues、glvalues和prvalues? Xvalues是rvalues(以及prvalues),标准规定如下:

第二种情况是当引用被绑定到一个临时变量时。引用绑定的临时变量或者是引用绑定的子对象的完整对象在引用的生命周期内保持不变,但有例外:

然而,存在一些文章对此进行了争论: rvalue引用是否允许悬空引用? xvalue和prvalue对于非POD对象的允许使用或行为差异的示例是什么? 请问有人可以澄清这个问题吗?微软视觉C++库(MSVC)这次是正确的吗?
1个回答

3

X值可能是rvalue,但这并不意味着它们是“临时”的。临时对象的生存期延长来自于它们是“临时”的这个事实,而不是它们的值类别。

我特意不知道运算符处理的顺序(这样,我就迫使自己编写代码,要么使用显式括号,要么根本不关心顺序)。你的特定的adder示例代码,在此重复一下,确实关心:

template <class T>
struct addable
{
    friend T operator +( const T& lhs, const T& rhs )
    {
        return std::move(T(lhs) += rhs); 
    }
    friend T operator +( const T& lhs, T&& rhs )
    {
        return std::move(T(lhs) += std::move(rhs));
    }   
    friend T&& operator +( T&& lhs, const T& rhs ) 
    {
        return std::move(lhs += rhs);
    }               
    friend T&& operator +( T&& lhs, T&& rhs ) 
    {
        return std::move(lhs += std::move(rhs)); 
    }
};

如果+运算符是从右往左执行的,那么t1 + t2 + t3会被计算为t1 + (t2 + t3)。调用t2 + t3将调用第一个重载,因此产生一个临时变量,得到t1 + temp。由于临时变量更倾向于绑定到一个右值引用上,因此该表达式将调用第二个重载,其也将返回一个临时变量。
然而,如果+运算符从左往右执行,那么你会得到(t1 + t2) + t3。这给我们temp + t1,这会导致问题。它将调用第三个重载。该函数的lhs参数是一个T&&,是对临时变量的引用。你返回相同的引用。这意味着你返回了对临时变量的引用。但是C++不知道这一点;它只知道你正在返回对某个东西的引用。
然而,这个“东西”在最后一个表达式(分配给新变量,可以是值类型或引用类型)被评估之后就要被销毁了。记住:C++不知道这个函数将返回对其第一个参数的引用。因此它无法知道用于函数操作数的临时变量的寿命需要扩展到存储返回引用的寿命。
顺便说一句,这就是为什么带有auto和相关内容的表达式树可能很危险。因为创建的内部临时变量无法由新临时变量或存储在各种对象中的引用保留。C++没有办法做到这一点。
所以谁是正确的取决于运算符解析的顺序。然而,我更喜欢我的解决方案:不要依赖语言的这些角落,只需绕过它们。停止从这些重载中返回T&&,而是将值移动到临时变量中。这样,它保证能够正确工作,你也不必不断地检查标准以确保你的代码能够正常工作。
此外,顺便说一下,我认为运算符+实际上修改其中一个参数有点粗鲁。
然而,如果您坚持要知道谁是正确的,那么GCC是正确的。来自第5.7节,第1页:

加法和减法运算符按从左到右分组。

所以,它不应该起作用。
注意:Visual Studio允许T &r2 = t1 + t2 + t3;编译为(非常让人恼火的)语言扩展。您应该已经得到了警告。

我不是M$网站上的发帖人,只是感到困惑。我甚至没有使用MSVC,但我确实担心我的代码含义。 - user1095108
@user1095108:我在底部添加了一个附录。 - Nicol Bolas
你解释得很好,但是能否指出标准的相关部分呢?如果我理解正确,返回一个右值引用到一个临时对象会自动导致悬空引用。 - user1095108
你所说的“Xvalues可能是rvalues”指的是什么?它们确实是rvalues。 - user1095108
2
"t1 + t2"将拥有完整的表达式生命周期...通过引用函数参数绑定并不限制其生命周期... - Johannes Schaub - litb
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接