我刚刚看到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更好吗?
答案 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
不会移动任何对象,而是将它们转换为右值引用。因此,由于超载分辨率,将会发生两件事情:
const
左值引用的事实,因此运行构造函数的运气复制构造函数是重载决策的匹配。现在或多或少同样适用于复制分配和移动分配。这样做的:
someclassvar = other.someclassvar;
会将other.someclassvar
复制到someclassvar
。为什么?由于超载解决规则。但是,如果你这样做:
someclassvar = std::move(other.someclassvar);
如果someclassvar
有一个移动赋值运算符,那么出于与上面解释的相同的原因,它将被引发。另一方面,如果someclassvar
没有移动赋值运算符,则会引发其赋值运算符。这里没有涉及构造函数,因为该语句是赋值。