为什么需要唯一指针中的移动构造函数和移动赋值构造函数?

For what is the move constructor and move assignment constructor in Unique Pointers needed?

我有一个 unique_ptr 的简化示例。我想知道唯一指针中的移动构造函数和移动赋值运算符需要什么? 如果我正确理解移动构造函数(并传递右值),这两行代码的结果应该相同。

UniquePointer<T> a(new T);
UniquePointer<T> a(UniquePointer<T>(new T));

这里是简化的 UniquePointer 代码:

template<typename T> class UniquePointer {
    T* m_ptr;
public:
    UniquePointer(const UniquePointer&) = delete;
    UniquePointer& operator=(const UniquePointer&) = delete;
    UniquePointer(UniquePointer&& rhs);
    UniquePointer& operator=(UniquePointer&& rhs);
    UniquePointer(T* ptr) : m_ptr(ptr) { }
    T* operator->() const { return m_ptr; }
    T& operator*() const { return *m_ptr; }
    T* get() const { return m_ptr; }
    ~UniquePointer() { delete m_ptr; }
};

首先调用常规构造函数UniquePointer(T* ptr)(不是移动构造函数)。当您传入 UniquePointer 类型的右值时,第二次调用移动构造函数 UniquePointer(UniquePointer&& rhs),然后删除复制构造函数。

当你这样做的时候你也需要移动构造函数

UniquePtr<T> ptr = std::move(some_old_unique_ptr);

在这种情况下,您需要从旧的 std::move,因为旧的是 lvalue。在已构造的对象上调用移动赋值运算符

ptr = std::move(yet_another_ptr); // invokes the move assignment operator

至于为什么需要它们,那是因为设计。这些对象是不可复制的,因此您需要移动它们。

std::unique_ptr 需要移动构造函数和移动赋值运算符,因为它是一个不可复制的对象,因此是唯一的。因为它是不可复制的,所以需要一种方法将它传递给事物,从而移动操作来处理它。

如果您需要将所有权从一个范围转移到另一个范围,则需要一个单独的对象。由于您不能(也不想)复制 unique_ptr,这意味着您需要移动它。例如,当从函数返回 unique_ptr 时。

std::unique_ptr<Foo> func()
{
    std::unique_ptr<Foo> ptr(new Foo);
    ...
    return ptr;
}

这需要移动构造函数或复制构造函数。另一个常见用例是从构造函数参数初始化 class 成员。

class Widget
{
public:
    Widget(std::unique_ptr<Foo> _foo_ptr)
       :foo_ptr(std::move(_foo_ptr))
    {}
private:
    std::unique_ptr<Foo> foo_ptr;
};