为什么需要唯一指针中的移动构造函数和移动赋值构造函数?
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;
};
我有一个 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;
};