我试图理解移动构造函数的实现。我们都知道,如果我们需要管理C++类中的资源,就需要实现规则5 (C++编程)。
微软给了我们一个例子:https://msdn.microsoft.com/en-us/library/dd293665.aspx。
这里有一个更好的方法,它使用复制交换来避免代码重复:动态分配对象数组
// 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
}在移动构造函数中,直接:
// Can we write src.swap(*this);
// or (*this).swap(src);因为我认为(*this) = std::move(src)更复杂一些。因为如果我们无意中写为(*this) = src,它将调用普通赋值操作符,而不是移动赋值运算符。
除了这个问题,在微软的例子中,他们写了这样的代码:在移动赋值操作符中,我们需要检查自赋值吗?这有可能发生吗?
// 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;
}发布于 2016-04-04 14:32:27
一种方法是实现默认构造函数、复制构造函数和swap函数。
然后实现移动构造函数,使用前三个操作复制和移动赋值操作符。
例如:
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中使用了这个成语,那么一旦添加了移动构造函数,就可以得到移动分配,而无需编写一行代码。
在某些情况下,这个成语可能不是最有效的。。因为复制运算符总是先构造一个临时的,然后与它交换。通过手工编写赋值操作符,可以获得更好的性能。如果有疑问,请检查优化的程序集输出并使用分析器。
发布于 2020-07-07 15:37:28
我也在互联网上寻找实现移动构造函数和移动分配的最佳方法。有几种方法,但都不是完美的。
以下是我迄今为止的调查结果。
下面是我作为示例使用的一个Test类:
class Test {
private:
std::string name_;
void* handle_ = nullptr;
public:
Test(std::string name)
: name_(std::move(name))
, handle_(malloc(128))
{
}
~Test()
{
if(handle_) free(handle_);
}
Test(Test&& other) noexcept; // we are going to implement it
Test& operator=(Test&& other) noexcept; // we are going to implement it
void swap(Test& v) noexcept
{
std::swap(this->handle_, v.handle_);
std::swap(this->name_, v.name_);
}
private:
friend void swap(Test& v1, Test& v2) noexcept
{
v1.swap(v2);
}
};方法1:向前直线‘n’
Test::Test(Test&& other) noexcept
: handle_(std::exchange(other.handle_, nullptr))
, name_(std::move(other.name_))
{
}
Test& Test::operator=(Test&& other) noexcept
{
if(handle_) free(handle_);
handle_ = std::exchange(other.handle_, nullptr);
name_ = std::move(other.name_);
return *this;
}优点
缺点
方法2:破坏+建筑
Test::Test(Test&& other) noexcept
: handle_(std::exchange(other.handle_, nullptr))
, name_(std::move(other.name_))
{
}
Test& Test::operator=(Test&& other) noexcept
{
this->~Test();
new (this) Test(std::move(other));
return *this;
}优点
缺点
方法3:复制‘n’跳槽
Test::Test(Test&& other) noexcept
: handle_(std::exchange(other.handle_, nullptr))
, name_(std::move(other.name_))
{
}
Test& Test::operator=(Test&& other) noexcept
{
Test (std::move(other)).swap(*this);
return *this;
}或复制和移动操作符2 in-1:
Test& Test::operator=(Test other) noexcept
{
swap(other, *this);
return *this;
}优点
缺点
swap函数中交换数据成员时创建的更小的对象方法4:通过移动分配移动构造函数
这就是你在MSDN上发现的
Test::Test(Test&& other) noexcept
{
*this = std::move(other);
}
Test& Test::operator=(Test&& other) noexcept
{
if(handle_) free(handle_);
handle_ = std::exchange(other.handle_, nullptr);
name_ = std::move(other.name_);
return *this;
}优点
缺点
链接
更多答案
https://stackoverflow.com/questions/36405412
复制相似问题