C ++ nrvo / copy elision,括号中带有return语句

时间:2018-02-12 15:06:27

标签: c++ language-lawyer copy-elision nrvo

我正在使用以下代码愚弄,并使用我的visual studio 2017应用程序和两个不同的在线编译器得到了不同的结果。在发布模式下,visual studio在两种情况下都会忽略复制/移动,而两个在线编译器只是在没有表达的返回语句的情况下执行此操作。我的问题是:谁是正确的,更重要的是什么是承保规则。 (我知道您可以将括号与decltype(auto)语法结合使用。但这不是当前的用例。)

示例代码:

#include <iostream>
#include <cstdio>

struct Foo
{
    Foo() { std::cout << "default constructor" << std::endl; }
    Foo(const Foo& rhs) { std::cout << "copy constructor" << std::endl; }
    Foo(Foo&& rhs) { std::cout << "move constructor" << std::endl; }
    Foo& operator=(const Foo& rhs) { std::cout << "copy assignment" << std::endl; return *this; }
    Foo& operator=(Foo&& rhs) { std::cout << "move assignment" << std::endl; return *this; }
};

Foo foo_normal()
{
    Foo a{};
    return a;
}

Foo foo_parentheses()
{
    Foo a{};
    return (a);
}

int main()
{
    auto a = foo_normal();
    auto b = foo_parentheses();
    std::getchar();
}

在线编译器1: http://cpp.sh/75bux

在线编译器2: http://coliru.stacked-crooked.com/a/c266852b9e1712f3

发布模式下visual studio的输出是:

default constructor
default constructor

在另外两个编译器中,输出是:

default constructor
default constructor
move constructor

2 个答案:

答案 0 :(得分:4)

这是the relevant quote from the standard

  

在下列情况下(可以合并以消除多份副本),允许复制/移动操作(称为复制省略)的省略:

     

(1.1) - 在具有类返回类型的函数的return语句中,当表达式是非易失性自动对象的名称时(除了函数参数或由异常声明引入的变量) handler([except.handle]))具有与函数返回类型相同的类型(忽略cv-qualification),通过将自动对象直接构造到函数调用的返回对象中,可以省略复制/移动操作/ p>

所以要求是

  1. 在退货声明中
  2. in a function
  3. 带有类返回类型
  4. 当表达式是非易失性自动对象的名称时(除了函数参数或由处理程序的异常声明引入的变量([except.handle]))
  5. 与函数返回类型
  6. 具有相同类型(忽略cv-qualification)

    我认为满足要求1,2,3和5,但要求4则不然。 (a)不是对象的名称。因此,对于给定的代码,copy-elision不适用。由于移动构造函数具有副作用,因此也不能在as-if规则下省略。

    因此gcc是对的,视觉工作室(和clang)在这里是错误的。

答案 1 :(得分:3)

海湾合作委员会是对的。

根据[class.copy.elision] paragraph 1

  

在以下情况下(允许合并以消除多份副本),允许复制/移动操作的省略,称为复制省略

     
      
  • 在具有类返回类型的函数中的return语句中,当表达式非易失性自动对象的名称时(除了函数参数或由异常 - 声明引入的处理程序([except.handle]))具有相同类型的函数(忽略cv-qualification)作为函数返回类型,通过将自动对象直接构造到函数调用的返回对象中,可以省略复制/移动操作

  •   
  • ...

  •   

return语句中的括号表达式不符合复制省略的标准。

事实上,在CWG 1597的解析之前,return语句中带括号的id-expression甚至不能被视为执行移动的右值。