返回本地对象是否需要移动语义?

Bos*_*son 16 c++ c++11

当按值返回本地对象时,C++编译器可以通过利用移动语义优化不必要的副本(复制省略).
" 可以优化"意味着如果不满足适当的条件,则行为应该基于副本回退到默认的值语义返回.
因此,据我所知,按值返回可复制对象始终有效.

但编译器(clang和gcc)似乎不同意我的解释,如下面的MWE所示.

class Foo {
public:
    Foo();
    Foo(const Foo&);
    Foo(Foo&&) = delete;
}

Foo f() { return Foo(); }  // error: call to explicitly deleted constructor of 'Foo'
Foo g() { Foo a; return a; }  // gcc complains, clang is fine
Foo x = g();  // error: call to explicitly deleted constructor of 'A'
Run Code Online (Sandbox Code Playgroud)

Q1:按值返回是否要求对象可移动?
Q2:如果没有,gcc和clang在我的MWE上行为不端,还是我错过了其他的东西?

Ker*_* SB 32

您只是满足重载Foo()决策的预期行为:是一个右值,因此重载决策将构造函数Foo(Foo&&)视为最佳匹配.由于删除了该重载,因此您的程序格式错误.此外,还有一个特殊的规则,即表示Foo a; return a;也将执行重载解析,就像a首先是rvalue一样.(该规则基本适用于退货声明符合复制条款的情况.)

这一切都按预期工作.是你删除了重载,所以你明确要求禁止这样的结构.

请注意,"真实"代码通常不会遇到此障碍,因为只要声明了复制构造函数,您的类就根本不会有任何移动构造函数.但你不好意思地说,"不,实际上我确实想要一个移动构造函数,如果有人试图使用它,我希望它是一个错误".

  • tl; dr关键是删除的移动构造函数与没有移动构造函数不同. (14认同)
  • @LightnessRacesinOrbit请注意,如果隐式或显式默认,则重载解析将忽略已删除的移动构造函数,但如果已明确删除则不会. (2认同)

Ant*_*vin 8

关于这个:

Foo g() { Foo a; return a; }  // gcc complains, clang is fine
Run Code Online (Sandbox Code Playgroud)

海湾合作委员会是对的,这不应该因为[class.copy]/32(强调我的)而编译:

当满足复制/移动操作的省略标准时,但不满足异常声明,并且要复制的对象由左值指定,或者当return语句中的表达式是(可能带括号的)id表达式时命名具有在最内层封闭函数或lambda-expression的body或parameter-declaration-clause中声明的自动存储持续时间的对象,首先执行用于选择复制的构造函数的重载决策,就好像该对象由rvalue指定一样.如果第一个重载决策失败或未执行,或者所选构造函数的第一个参数的类型不是对象类型的rvalue引用(可能是cv-qualified),则再次执行重载决策,将对象视为左值.[ 注意: 无论是否发生复制省略,都必须执行此两阶段重载决策.如果未执行elision,它将确定要调用的构造函数,并且即使调用被省略,也必须可以访问所选的构造函数. - 尾注 ]

因此,实现应该为elision选择移动构造函数,并且当它被删除时,程序是不正确的.