简体   繁体   English

如何正确定义移动构造函数?

[英]How to properly define a move constructor?

I did search the internet and found 3 ways of defining a move constructor: 我确实搜索了互联网并找到了3种定义移动构造函数的方法:

  1. Relying on compiler: 依靠编译器:

     T(T&& other) = default; 
  2. Dereference this pointer: 取消引用this指针:

     T(T&& other) { *this = std::move(other); } 
  3. Explicitly reassign all members: 明确重新分配所有成员:

     T(T&& other) { Ta = other.a; Tb = other.b; //... } 

Which one is the proper way ? 哪一个是正确的方法? (And is the second one even correct?) (第二个甚至是正确的吗?)

The proper generic way is to move-construct each member, but that's what the defauted version does anyway: 正确的通用方法是移动构造每个成员,但这就是取消版本所做的事情:

T(T && rhs)
: a(std::move(rhs.a))
, b(std::move(rhs.b))
{  }

As a rough rule, you should use the default definition if this is all you need, and you should write an explicit move constructor if you're doing something that explicitly implements move semantics, such as a unique-ownership resource manager: 作为一个粗略的规则,如果这是您所需要的,则应该使用默认定义,如果您正在执行显式实现移动语义的操作,则应编写显式移动构造函数,例如唯一所有权资源管理器:

URM(URM && rhs)
: resource(rhs.resource)
{
    rhs.resource = nullptr;
}

The indicator for whether this is appropriate is probably whether your class has a user-defined destructor. 这是否合适的指标可能是您的类是否具有用户定义的析构函数。 In the example, the destructor would release the managed resource, and this must happen only once, so the moved-from object must be modified. 在该示例中,析构函数将释放托管资源,并且这必须仅发生一次,因此必须修改移动的对象。


This is unrelated, but since you are mentioning the assignment operator, here's the popular swap-and-assign/swap idiom: 这是无关的,但由于你提到赋值运算符,这里是流行的swap-and-assign / swap惯用法:

void swap(URM & rhs) noexcept      // assume members are noexcept-swappable!
{
    using std::swap;
    swap(resource, rhs.resource);
    // ...
}

URM & operator=(URM rhs) noexcept  // pass by value
{
    rhs.swap(*this);
    return *this;
}

The beauty of this approach is that you only need one single version of the assignment operator that works for temporaries and non-temporaries alike, using move construction when appropriate, and as long as all your members are well-designed, you also only need one single swap function. 这种方法的优点在于,您只需要一个适用于临时和非临时工作的赋值运算符,在适当的时候使用移动构造,只要您的所有成员都经过精心设计,您也只需要一个单swap功能。 On top of that, if the swap function doesn't throw (which a well-designed class should allow), then your assignment operator doesn't throw, since all the possible exceptions would already occur at the call site. 最重要的是,如果交换函数没有抛出(设计良好的类应允许),那么你的赋值运算符不会抛出,因为所有可能的异常都会在调用站点发生。

T(T&& other)
: data(0) // initialize members
{
    swap(other); // where the class has a member function swap or std::swap(this->data, other.data)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM