Move ctor 是否在所有情况下都有效?
Will the Move ctor effective in all scenarios?
我刚刚从 https://msdn.microsoft.com/en-us/library/dd293665.aspx 中看到下面的代码,它展示了如何实现移动 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;
}
此处随此代码一起出现的 question/doubt 之一是:如果 class MemoryBlock
包含一些 class 类型的成员变量(比如 someclassvar
), 如果该成员相当大, 修改后的 move ctor 中的以下行是否有效 (假设此 someclassvar
没有 move 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
同时包含移动赋值和复制赋值,这应该调用?
像这样的所有情况下,move ctor 是否仍然有效?如果没有,复制ctor更好吗?
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
class 有 move ctor/ move =
那么 std::move(other.someclassvar)
会 move
否则会 copy
.
如果需要高效,请为 class someclassvar
提供 move ctor/ move =
。
首先,在任何构造函数中,如果可能,您应该更愿意在构造函数的初始化列表中初始化您的成员。其次,在移动构造函数中,您应该使用 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
没有移动赋值运算符,它的赋值运算符将被调用。这里不涉及构造函数,因为该语句是一个赋值。
我刚刚从 https://msdn.microsoft.com/en-us/library/dd293665.aspx 中看到下面的代码,它展示了如何实现移动 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;
}
此处随此代码一起出现的 question/doubt 之一是:如果 class MemoryBlock
包含一些 class 类型的成员变量(比如 someclassvar
), 如果该成员相当大, 修改后的 move ctor 中的以下行是否有效 (假设此 someclassvar
没有 move 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
同时包含移动赋值和复制赋值,这应该调用?
像这样的所有情况下,move ctor 是否仍然有效?如果没有,复制ctor更好吗?
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
class 有 move ctor/ move =
那么 std::move(other.someclassvar)
会 move
否则会 copy
.
如果需要高效,请为 class someclassvar
提供 move ctor/ move =
。
首先,在任何构造函数中,如果可能,您应该更愿意在构造函数的初始化列表中初始化您的成员。其次,在移动构造函数中,您应该使用 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
没有移动赋值运算符,它的赋值运算符将被调用。这里不涉及构造函数,因为该语句是一个赋值。