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

Implicitly treating returned lvalue as rvalue

本文关键字:处理 返回      更新时间:2023-10-16

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

在具有类返回类型的函数中的返回语句中,当表达式是与函数返回类型具有相同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)不是一个名称,而是一个带括号的表达式。我是对还是错?

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

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

5.1.1.1概述【expr.prim.General】

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


关于constexpr条件运算符[╳]

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

我现在更仔细地研究了这个标准,它没有说常量条件表达式与如果只有";返回"表达式就会被写入。

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

关于返回*&结果[╳]

在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

除非另有说明,带圆括号的表达式等效于其未带圆括号表达式(例如,在ADL规则中执行,或者在另一个示例中通过decltype执行)。当某些东西以这种方式不等价时,有时可能会很棘手(例如,ADL规则没有明确提到"未加括号",但它们使用了明确的语法非词尾和明确表示parens不被视为等价的例子)。

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

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