如何为 unique_ptr 包装器 class 定义 operator=?

How to define the operator= for a unique_ptr wrapper class?

我正在尝试为 std::unique_ptr 创建一个包装器 class,目前它只需要支持 unique_ptr 的基本操作,但在未来这将有更多功能。

template<typename T>
class Unique {
public:
    Unique(std::nullptr_t) { pointer = nullptr; }
    template<typename ...Args>
    Unique(Args&&... args) { pointer = std::make_unique<T>(std::forward<Args>(args)...); }

    T operator*() const { return *pointer.get(); }
    T* operator->() const { return pointer.get(); }

    // operator=() ?
private:
    std::unique_ptr<T> pointer;
};

Unique<Foo> foo() 工作得很好,但是当我尝试做 Unique<Foo> bar = foo 时出现问题,编译器错误说

error: no matching function for call to ‘Foo::Foo(Unique\<Foo\>&)’ { return unique\_ptr<\_Tp>(new \_Tp(std::forward<\_Args>(\_\_args)...)); }

如何定义一个 operator= 来完成这项工作?

unique_ptr 的全部意义在于它是唯一的——只能有一个指向一个对象的指针,并且该指针不能被复制。

如果您想要复制包含 unique_ptr 的 class,您可能希望它创建一个新的 unique_ptr 到指向对象的副本:

template<typename T> Unique<T> &Unique<T>::operator=(const Unique<T> &a) {
    if (a.pointer)
        pointer = std::make_unique<T>(*a.pointer);
    else
        pointer.reset();
    return *this;
}

这仅在 T 不是动态的情况下有效 class -- 如果 T 实际上是一个基数 class 并且您通常有指向 subblass 的指针,这将无效并且会切片对象(这是坏的)。如果你的动态基础 class 有一个克隆方法或类似的方法,你也许可以做一些事情。

您可能还需要一个 move-assignment 运算符:

template<typename T> Unique<T> &Unique<T>::operator=(Unique<T> &&a) {
    pointer = std::move(a.pointer);
    return *this;
}

或者你可以把

Unique<T> &operator=(Unique<T> &&) = default;

在 class 中让编译器为您创建一个默认值(除非有其他字段,否则与此相同)。

事实证明,正如@che.wang 所指出的,我实际上需要一个基于 unique_ptr reference 中的 (2) 的 Converting Assignment Constructor,例如:

template<typename U> Unique(Unique<U>&& other) { pointer = std::move(other.pointer); }