为什么移动运算符不只是析构函数+移动构造函数

Why isn't move operator just destructor + move constructor

本文关键字:移动 析构函数 构造函数 运算符 为什么      更新时间:2023-10-16

考虑以下片段:

class Foo
{
public:
/* ... */
Foo(Foo &&other);
~Foo();
Foo &operator=(Foo &&rhs);
private:
int *data;
};
Foo::Foo(Foo &&other)
{
data = other.data;
other.data = nullptr;
}
Foo::~Foo()
{
delete data;
}
Foo &Foo::operator=(Foo &&other)
{
if (this == &other) return *this;
delete data;            /* SAME AS DESTRUCTOR */
data = other.data;      /* SAME AS MOVE CONSTRUCTOR */
other.data = nullptr;
return *this;
}

这个片段几乎就是我最终得到的。

为什么我们需要一个移动算子,如果它的行为可以推导出来
如果此语句不正确,那么在哪种情况下,move运算符的行为与析构函数+move构造函数不同?

因为它不能被推导出来。语言不知道拆除int*涉及到什么。也许你还有其他家务活要做。

事实上,如果你正在编写一个移动构造函数,你通常会有其他内务处理要执行,因为如果你所做的只是delete动态内存,那么你应该使用智能指针,根本不需要编写自己的移动构造函数。

此外,您正在重复代码中的逻辑。你可以"重用析构函数"通过避免这些滑稽动作在你的移动构造函数&assigner,简单地交换指针,并让从对象的析构函数中移出的对象在时间到来时做它通常做的事情:

Foo::Foo(Foo&& other)
: data(nullptr)
{
*this = std::move(other);
}
Foo& Foo::operator=(Foo&& other)
{
std::swap(this->data, other.data);
return *this;
};

(免责声明:可能有一种更惯用的方法,我记不清了,但你明白了。)

现在样板房少了很多。所以你可以看到,即使如果语言为你推导了移动构造函数,它也不会涉及析构函数。

只需对类进行一点更改,就可以

class Foo
{
public:
/* ... */
// deleted copy constructor and copy assignment
// generated destructor, move constructor and move assignment
private:
std::unique_ptr<int> data;
};