使用 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_ptr
的 operator=()
不接受对另一个 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 = b
、a.ptr
和 b.ptr
后指向完全相同的对象(即存储相同的指针),请使用共享指针。在这种情况下你绝对不应该使用唯一指针,因为调用 a
或 b
的析构函数会破坏指向的对象,使 a
或 b
无效状态。
如果您希望在调用 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;
}
但是请注意,这仅在 baseClass
为 final
时有效(不太可能考虑名称...),即 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
可能最终处于不同的状态。
我有一个用户定义的 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_ptr
的 operator=()
不接受对另一个 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?
这是 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 = b
、a.ptr
和 b.ptr
后指向完全相同的对象(即存储相同的指针),请使用共享指针。在这种情况下你绝对不应该使用唯一指针,因为调用 a
或 b
的析构函数会破坏指向的对象,使 a
或 b
无效状态。
如果您希望在调用 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;
}
但是请注意,这仅在 baseClass
为 final
时有效(不太可能考虑名称...),即 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
可能最终处于不同的状态。