Move ctor会在所有场景中有效吗?

时间:2016-04-20 11:22:35

标签: c++ move-semantics

我刚刚看到https://msdn.microsoft.com/en-us/library/dd293665.aspx中的以下代码,其中显示了如何实现move ctor:

MemoryBlock(MemoryBlock&& other)
   : _data(nullptr)
   , _length(0)
{
   std::cout << "In MemoryBlock(MemoryBlock&&). length = " 
             << other._length << ". Moving resource." << std::endl;

   // Copy the data pointer and its length from the 
   // source object.
   _data = other._data;
   _length = other._length;

   // Release the data pointer from the source object so that
   // the destructor does not free the memory multiple times.
   other._data = nullptr;
   other._length = 0;
}

这里提出的问题/疑问之一是:如果类MemoryBlock包含一些类类型成员变量(比如someclassvar),并且如果该成员相当大,那么修改后的行动中的以下行有效(假设此someclassvar没有移动ctor)?

MemoryBlock(MemoryBlock&& other)
   : _data(nullptr)
   , _length(0),someclassvar(other.someclassvar)
{
   std::cout << "In MemoryBlock(MemoryBlock&&). length = " 
             << other._length << ". Moving resource." << std::endl;

   // Copy the data pointer and its length from the 
   // source object.
   _data = other._data;
   _length = other._length;
  // someclassvar=other.someclassvar;

   // Release the data pointer from the source object so that
   // the destructor does not free the memory multiple times.
   other._data = nullptr;
   other._length = 0;
   delete other.someclassvar;
}

这里someclassvar = other.someclassvar;我相信这会调用复制赋值运算符,这种行为是否有效?而且,如果someclassvar包含移动分配和复制分配,可以预期调用吗?

在这种情况下,移动ctor是否仍然有效?如果没有,复制ctor更好吗?

2 个答案:

答案 0 :(得分:1)

MemoryBlock(MemoryBlock&& other)
   : _data(nullptr)
   , _length(0), someclassvar(std::move(other.someclassvar))
{
   std::cout << "In MemoryBlock(MemoryBlock&&). length = " 
             << other._length << ". Moving resource." << std::endl;

   // Copy the data pointer and its length from the 
   // source object.
   _data = other._data;
   _length = other._length;

   // Release the data pointer from the source object so that
   // the destructor does not free the memory multiple times.
   other._data = nullptr;
   other._length = 0;
}

如果someclassvar班级有move ctor/ move =,那么std::move(other.someclassvar) move将会copy

如果需要高效,请为move ctor/ move =课提供someclassvar

答案 1 :(得分:1)

首先,在任何构造函数中,如果可能,您应该更喜欢在构造函数的初始化列表中初始化您的成员。其次,在移动构造函数中,您应该使用std::move移动可移动的成员,或者如果它们不可移动则复制它们:

MemoryBlock(MemoryBlock&& other)
: _data(std::move(other._data)), 
  _length(std::move(other._length)),
  someclassvar(std::move(other._someclassvar)) {
   // optionally set state of moved object
}

现在std::move不会移动任何对象,而是将它们转换为右值引用。因此,由于超载分辨率,将会发生两件事情:

  1. 如果要移动的类型具有用户定义或隐式定义的移动构造函数,则此移动构造函数将被激发,因此,该对象将相应地移动到其新主机。
  2. 如果要移动的类型没有任何已定义的移动构造函数,那么将激发该类型的复制构造函数。这归因于rvalue引用可以绑定到const左值引用的事实,因此运行构造函数的运气复制构造函数是重载决策的匹配。
  3. Live Demo

    现在或多或少同样适用于复制分配和移动分配。这样做的:

    someclassvar = other.someclassvar;
    

    会将other.someclassvar复制到someclassvar。为什么?由于超载解决规则。但是,如果你这样做:

    someclassvar = std::move(other.someclassvar);
    

    如果someclassvar有一个移动赋值运算符,那么出于与上面解释的相同的原因,它将被引发。另一方面,如果someclassvar没有移动赋值运算符,则会引发其赋值运算符。这里没有涉及构造函数,因为该语句是赋值。