19

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

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

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

因此我们可以写:

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

但是,我注意到 g++ 4.6.3 也接受不是名称的左值,例如:

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

相比之下,return rand() ? result : result;行不通。编译器的优化器是否干扰了语言语义?正如我解释的标准,return (result);不应该编译,因为(result)不是一个名字,而是一个带括号的表达式。我是对还是错?

4

2 回答 2

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>;

关于退货 *&result; [╳]

在 C99 中明确指出,*&result完全等同于编写result,而在 C++ 规范中并非如此。

尽管我们都同意 using*&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
于 2012-07-16T18:20:28.340 回答
1

除非另有说明(例如,在 ADL 规则中所做的那样,或者在另一个示例中通过 decltype 完成),否则带括号的表达式等同于它们未带括号的表达式。有时,当某些东西以这种方式不等价时,有时会很棘手(例如,ADL 规则没有明确提到“无括号”,但它们使用了显式的非终结语法,并且示例清楚地表明括号不是认为是等价的)。

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

int a = 42;
int *p = 0 * a;
于 2012-07-17T20:46:55.163 回答