使用 unique_ptr 数据成员重载用户定义类型的 operator=

Overloading operator= of user defined type with unique_ptr data member

我有一个用户定义的 class,它有一个 std::unique_ptr 成员。我正在尝试重载赋值运算符以将相同类型的对象新建到 unique_ptr 成员或将值分配给 ptr 值。

class object
{
    public:
    // POD types

    object& operator=(const object& _obj);

    std::unique_ptr<baseClass> ptr;
} 

我试过使用:

std::unique_ptr::swap()

但是交换函数是非常量的,所以我尝试分配以下结果:

std::unique_ptr::get()

ptr然后呼叫:

std::unique_ptr::release()

但 release 也是非常量,所以我不能保证 ptr 会被正确销毁,因为旧的 ptr 仍然拥有所有权。 las,unique_ptroperator=() 不接受对另一个 unique_ptr 的非常量引用,所以我选择将 operator= 设置为 class.

object& object::operator=(const object& _obj)
{
    //POD types use operator= as normal
    ptr.reset(nullptr);

    return *this;
}

稍后只需调用 setPtr() 方法来设置 ptr。我只想检测类型并使用以下方法分配 ptr

ptr.reset(new detectedType );

但是整个 Stack Overflow 和我首选的搜索引擎的共识是检测这样的类型将是一个设计缺陷。我的问题是:我是否忽略了一些简单的事情,是否有更好的方法为具有 unique_ptr 成员的用户定义类型重载赋值运算符?

post 编辑前: 我将参数更改为 object& 而不是 const object& 并且它起作用了。这是纠正此问题的好方法,还是我应该尝试仅使用对其他 class?

的 const 引用

这是 mutable 关键字的一个很好的用例。如果将 ptr 声明为 mutable,则表示即使 class 的实例在语义上是常量,它也必须对特定数据成员执行非常量操作。如下声明你的class,你应该能够实现你最初使用swap的想法:

class object
{
    public:
    // POD types

    object& operator=(const object& _obj);

    mutable std::unique_ptr<baseClass> ptr;
} 

My question is: am I overlooking something simple and is there a better way to overload the assignment operator for user defined types that have a unique_ptr member?

确实有。这分解为了解 C++ 中的智能指针的作用。通常你使用 std::unique_ptr 如果将有一个且只有一个对你的对象的引用。这就是为什么 std_unique_ptr 既不可复制构造也不可复制分配的原因。如果您使用 ptr.get() 手动创建 std::unique_ptr 的两个副本,如您在 post 中所述,您将最终处于无效状态,因为一旦一个副本离开范围, std::unique_ptr 析构函数也将破坏它指向的对象,使另一个 std::unqiue_ptr 处于无效状态(它指向已释放的内存位置)。因此,如果可能有多个对您的对象的引用,您应该改用 std::shared_ptr

在你的例子中,问题是你想达到什么目的?

如果您希望赋值运算符在调用 a = ba.ptrb.ptr 后指向完全相同的对象(即存储相同的指针),请使用共享指针。在这种情况下你绝对不应该使用唯一指针,因为调用 ab 的析构函数会破坏指向的对象,使 ab 无效状态。

如果您希望在调用 a = b 后,a.ptr 指向 *(b.ptr) 的独立副本,您确实可以使用唯一指针并像这样实现赋值运算符(前提是 baseClass 可复制):

object& object::operator=(const object& _obj)
{
    //POD types use operator= as normal
    ptr.reset(new baseClass(*_obj.ptr));

    return *this;
}

但是请注意,这仅在 baseClassfinal 时有效(不太可能考虑名称...),即 ptr 不会存储指向派生 class。否则,这将导致 BenVoigt 指出的 slicing

最后,通常预计调用 a = b 不会 而不会 改变 b。因此,让 ptr 成员可变并使用 swap 对我来说听起来不是个好主意。如果出于性能(或其他)考虑而想要实现此行为,我建议改为实现移动赋值运算符

object& object::operator=(object&& _obj)
{
    //POD types use operator= as normal
    ptr = std::move(_obj.ptr);

    return *this;
}

并调用 a = std::move(b),这表明 b 可能最终处于不同的状态。