将返回的左值隐式处理为右值

时间:2012-07-16 17:50:45

标签: c++ c++11 return move-semantics

12.8复制和移动类对象[class.copy]§31和§32说:

  

在具有类返回类型的函数的return语句中,当表达式是具有相同类型的非易失性自动对象(除函数或catch子句参数之外)的名称时cv-unqualified type作为函数返回类型,通过将自动对象直接构造为函数的返回值,可以省略复制/移动操作

     

当满足或将满足复制操作的省略标准时,除了源对象是函数参数,并且要复制的对象由左值指定,重载决策以选择构造函数首先执行复制,就像对象是由右值指定一样。

因此我们可以写:

unique_ptr<int> make_answer()
{
    unique_ptr<int> result(new int(42));
    return result;   // lvalue is implicitly treated as rvalue
}

但是,我注意到g ++ 4.6.3也接受 not names 的左值,例如:

    return (result);
    return *&result;
    return true ? result : result;

相比之下,return rand() ? result : result;不起作用。编译器的优化器是否会干扰语言语义?当我解释标准时,return (result);不应该编译,因为(result)不是名称,而是带括号的表达式。我是对还是错?

2 个答案:

答案 0 :(得分:10)

关于带括号的表达式 [√]

在谈论带括号的表达式时你错了,并且在返回并且只包含的名称时它不应该能够触发移动可移动的对象。

  

5.1.1 / 1一般[expr.prim.general]

     

带括号的表达式是一个主要表达式,其类型和   值与所附表达式的值相同。该   括号的存在不会影响表达式是否为左值。 除非另有说明,否则带括号的表达式可以在与可以使用所附表达式完全相同的上下文中使用,具有相同含义


关于constexpr 条件运算符 [╳]

我解释关于常量表达式编码运算符的标准的方式是使用return true ? result : result是表现良好,因为它是一个常量表达式,因此相当于返回结果;

我现在更仔细地阅读了标准,并且没有任何地方说常量条件表达式与只有“返回”表达式具有的相同写了。

true ? <expr1> : <expr2>; // this is not the same as just writing <expr1>;

关于 return *&amp; result; [╳]

在C99中,明确指出*&result完全等同于编写result,而不是C ++规范中的情况。

虽然我们都同意使用*&result确实会产生与result相同的左值,但根据标准*&result(当然)不是表达式“表达式是非易失性自动对象的名称”

当然,表达式包含一个合适的名称,但不仅仅是那个。


总结一下......

return result; // #1, OK

return (result);                  // as described earlier, OK
return true ? result : result;    // as described earlier, ill-formed
return rand () ? result : result; // as described earlier, ill-formed
return *&result;                  // as described earlier, ill-formed

答案 1 :(得分:1)

除非另有说明,否则括号内的表达式与其未表示的表达式等效(例如,在ADL规则中完成,或者在另一个示例中使用decltype)。当某些东西在某种程度上不等同于某种方式时(例如,ADL规则没有明确提到“未加密化”),它们有时会很棘手,但是它们使用了非终端的显式语法和示例,这些示例表明parens不是视为等同)。

对于其他问题:是的,GCC直接对AST进行了几次优化,使其接受各种无效程序,如下所示

int a = 42;
int *p = 0 * a;