为什么移动运算符不只是析构函数+移动构造函数
Why isn't move operator just destructor + move constructor
考虑以下代码段:
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;
}
这段代码几乎就是我最终得到的。
如果可以推断其行为,为什么我们需要移动运算符?
如果此语句不正确,在这种情况下,移动运算符的行为不同于析构函数 + 移动构造函数 ?
只要对您的 class 稍作改动,就可以。
class Foo
{
public:
/* ... */
// deleted copy constructor and copy assignment
// generated destructor, move constructor and move assignment
private:
std::unique_ptr<int> data;
};
因为无法推导。该语言不知道拆除您的 int*
涉及什么。也许您还有其他家务需要执行。
事实上,如果您正在编写一个移动构造函数,您 通常 需要执行其他内务处理,因为如果您所做的只是 delete
动态内存,你应该一直使用智能指针,根本不需要编写自己的移动构造函数。
此外,您在代码中重复逻辑。您 可以 "re-use the destructor" 通过在您的移动构造函数和分配器中避免这些滑稽动作,只需交换指针,并让移出对象的析构函数在时机成熟时执行它通常执行的操作:
Foo::Foo(Foo&& other)
: data(nullptr)
{
*this = std::move(other);
}
Foo& Foo::operator=(Foo&& other)
{
std::swap(this->data, other.data);
return *this;
};
(免责声明:可能有更惯用的方法,我不记得了,但你明白了。)
现在样板文件少了很多。所以你可以看到,即使 if 语言为你推导出移动构造函数,它也根本不会涉及析构函数。
考虑以下代码段:
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;
}
这段代码几乎就是我最终得到的。
如果可以推断其行为,为什么我们需要移动运算符?
如果此语句不正确,在这种情况下,移动运算符的行为不同于析构函数 + 移动构造函数 ?
只要对您的 class 稍作改动,就可以。
class Foo
{
public:
/* ... */
// deleted copy constructor and copy assignment
// generated destructor, move constructor and move assignment
private:
std::unique_ptr<int> data;
};
因为无法推导。该语言不知道拆除您的 int*
涉及什么。也许您还有其他家务需要执行。
事实上,如果您正在编写一个移动构造函数,您 通常 需要执行其他内务处理,因为如果您所做的只是 delete
动态内存,你应该一直使用智能指针,根本不需要编写自己的移动构造函数。
此外,您在代码中重复逻辑。您 可以 "re-use the destructor" 通过在您的移动构造函数和分配器中避免这些滑稽动作,只需交换指针,并让移出对象的析构函数在时机成熟时执行它通常执行的操作:
Foo::Foo(Foo&& other)
: data(nullptr)
{
*this = std::move(other);
}
Foo& Foo::operator=(Foo&& other)
{
std::swap(this->data, other.data);
return *this;
};
(免责声明:可能有更惯用的方法,我不记得了,但你明白了。)
现在样板文件少了很多。所以你可以看到,即使 if 语言为你推导出移动构造函数,它也根本不会涉及析构函数。