我试图理解move-constructor的实现。 我们都知道如果我们需要管理C ++类中的资源,我们需要实现五阶规则(C ++编程)。
Microsoft给我们举了一个例子:https://msdn.microsoft.com/en-us/library/dd293665.aspx
这是更好的一个,它使用copy-swap来避免代码重复: Dynamically allocating an array of objects
// C++11
A(A&& src) noexcept
: mSize(0)
, mArray(NULL)
{
// Can we write src.swap(*this);
// or (*this).swap(src);
(*this) = std::move(src); // Implements in terms of assignment
}
在move-constructor中,直接:
// Can we write src.swap(*this);
// or (*this).swap(src);
因为我认为(*this) = std::move(src)
稍微复杂一些。因为如果我们无意中写为(*this) = src
,它会调用普通赋值运算符而不是move-assignment-operator。
除了这个问题,在微软的例子中,他们编写了这样的代码:在move-assignment-operator中,我们是否需要检查自我分配?有可能发生吗?
// Move assignment operator.
MemoryBlock& operator=(MemoryBlock&& other)
{
std::cout << "In operator=(MemoryBlock&&). length = "
<< other._length << "." << std::endl;
if (this != &other)
{
// Free the existing resource.
delete[] _data;
// 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;
}
return *this;
}
答案 0 :(得分:6)
一种方法是实现默认构造函数,复制构造函数和swap
函数。
然后实现移动构造函数,使用前三个来复制和移动赋值运算符。
E.g:
struct X
{
X();
X(X const&);
void swap(X&) noexcept;
X(X&& b)
: X() // delegate to the default constructor
{
b.swap(*this);
}
// Note that this operator implements both copy and move assignments.
// It accepts its argument by value, which invokes the appropriate (copy or move) constructor.
X& operator=(X b) {
b.swap(*this);
return *this;
}
};
如果您在C ++ 98中使用过这个习惯用法,那么一旦添加了移动构造函数,就可以获得移动赋值而无需编写任何代码。
In some cases this idiom may be not the most efficient。因为复制操作符总是首先构造一个临时的,然后与它交换。通过手动编码赋值运算符,可以获得更好的性能。如有疑问,请检查优化的装配输出并使用分析器。
答案 1 :(得分:0)
我也在寻找Internet,以找到实现move构造函数和move分配的最佳方法。方法很少,但都不是完美的。
以下是我到目前为止的发现。
以下是我正在使用的Test
类作为示例:
class Test {
private:
void* handle_ = nullptr;
std::string name_;
public:
~Test();
Test(std::string name);
Test(Test&& other) noexcept;
Test& operator=(Test&& other) noexcept;
};
Test(Test&& other) noexcept
: handle_(std::exchange(other.handle_, nullptr))
, name_(std::move(other.name_))
{
}
Test& operator=(Test&& other) noexcept
{
if(handle_) close_handle(handle_);
handle_ = std::exchange(other.handle_, nullptr);
name_ = std::move(other.name_);
return *this;
}
Test& operator=(Test&& other) noexcept
{
if(&other == this) return *this;
this->~Test();
new (this) Test(std::move(other));
return *this;
}
operator=
在基类上运行,则将分配基类的VMT Test& operator=(Test&& other) noexcept
{
Test (std::move(other)).swap(*this);
return *this;
}
或复制和移动运算符2合1:
Test& operator=(Test other) noexcept
{
std::swap(other, *this);
return *this;
}
这就是您@Dongguo在MSDN上找到的内容
Test(Test&& other) noexcept
{
*this = std::move(other);
}
Test& operator=(Test&& other) noexcept
{
if(handle_) close_handle(handle_);
handle_ = std::exchange(other.handle_, nullptr);
name_ = std::move(other.name_);
return *this;
}