如果从函数返回,是否也会移动局部变量的成员子对象?

Xeo*_*Xeo 7 c++ local-variables move-semantics c++11

C++ 11标准规定,如果满足复制省略的条件(§12.8/31),则实现应将returned局部左值变量和函数参数视为rvalue first(move),如果重载解析不成功,则详细,然后将其视为左值(副本).

§12.8 [class.copy] p32

当满足或将满足复制操作的省略标准时,除了源对象是函数参数这一事实,并且要复制的对象由左值指定,重载决策选择复制的构造函数是首先执行,好像对象是由右值指定的.如果重载决策失败,或者所选构造函数的第一个参数的类型不是对象类型的rvalue引用(可能是cv-qualified),则再次执行重载决策,将对象视为左值.[ 注意:无论是否发生复制省略,都必须执行此两阶段重载决策.如果未执行elision,它将确定要调用的构造函数,并且即使调用被省略,也必须可以访问所选的构造函数.- 尾注 ]

这还包括成员子对象吗?我测试了以下代码段:

#include <iostream>

struct traced{
  traced(){ std::cout << "default ctor\n"; }
  traced(traced const&){ std::cout << "copy ctor\n"; }
  traced(traced&&){ std::cout << "move ctor\n"; }
};

struct X{
  traced t;
};

traced f(){
  X x;
  return x.t;
}

int main(){
  traced t = f();
}
Run Code Online (Sandbox Code Playgroud)

Ideone上的实例. GCC 4.7 ToT和Clang 3.1 ToT都不会显示"move ctor",这让我相信标准不包含成员子对象.

我忽略了什么吗?我的测试代码坏了吗?究竟是什么导致输出原样?

Die*_*ühl 6

返回子对象时,您无法忽略其构造.可以这样想:移动和复制elision本质上相当于在最终被移动或复制到的位置构建对象.这适用于完整的对象,因为将留出适当的空间.它不适用于子对象,因为您将构造封闭对象.即使它与子对象具有相同的大小,即有足够的空间,封闭对象也会被破坏,并且可能对子对象做有趣的事情.

实际上,这意味着不能省略对象的构建.

  • +1 - 但你应该注意会议! (2认同)
  • 虽然你所说的NRVO可能是真的,但复制到移动治疗并不一定如此.移动子对象而不是复制子对象没有任何技术问题.在诸如`return X().t;`之类的代码中,只需要移动一个子对象而不是整个对象. (2认同)