说,我有一个班级:
class GameObject ///header file
{
....
std::shared_ptr<Transform> transform;
}
///cpp file
//Copy Ctor
GameObject::GameObject(const GameObject& rhs)
:transform(rhs.transform)
{}
//Move CTor
GameObject::GameObject(GameObject&& rhs)
:transform(std::move(rhs.transform))
{}
rhs.transform.reset()
来取消分配rhs吗? return *this
?答案 0 :(得分:10)
您的复制和移动构造函数等效于隐式构造函数。删除它们。您不需要明确地将它们写出来,因为std::shared_ptr
的复制和移动构造函数正确地实现了这两个操作。
或者我需要在移动后致电
rhs.transform.reset()
取消分配rhs
吗?
不,移动后的对象将在移动后失去所有权:
shared_ptr(shared_ptr&& r) noexcept; template<class Y> shared_ptr(shared_ptr<Y>&& r) noexcept;
备注:除非
Y*
可转换为T*
,否则第二个构造函数不应参与重载决策。效果:从r构造一个shared_ptr实例。 后置条件:
*this
应包含旧值r
。r
应为空。r.get() == nullptr
。强>
对于复制和移动赋值运算符,它们也是等价的。移动分配将正确转移所有权,复制构造函数将执行浅层复制,以便shared_ptr
拥有所有权。
如果您想要一个浅拷贝(共享所有权),那么shared_ptr
是正确的工具。否则,如果您要实施唯一所有权,我建议您使用unique_ptr
。
答案 1 :(得分:1)
此代码是正确的。如果GameObject
可移动,则移动transform
非常有意义。 shared_ptr
移动构造函数将在此处为您做正确的事情 - 它将转移Transform
的所有权。你不需要调用reset()
,这是一个无关紧要的操作 - 你应该只需要依赖你的成员对象的移动构造函数来正确实现,对于它们肯定是shared_ptr
。
会员明智的副本是正确的,shared_ptr
会为您正确复制。
是。
请注意,如果您的类完全由实现了所有正确运算符的对象组成,则您不需要自己编写它们。默认构造函数和赋值运算符已经执行成员复制/移动,这完全正确。不必编写任何基本的5个函数称为Rule of Zero:
class GameObject {
std::shared_ptr<Transform> transform;
std::shared_ptr<SomethingElse> foo;
};
GameObject obj = ...;
GameObject obj2 = obj; // correct by default
GameObject obj3 = std::move(obj2); // correct by default
答案 2 :(得分:0)
根据标准,shared_ptr
的移动构造函数将原始shared_ptr
留空,因此不需要reset()
调用。
您编写的复制构造函数将在多个Transform
之间共享一个GameObject
对象。也许这就是你想要的。如果没有,您需要transform(new Transform(*rhs.transform))
。
基本上,但您使用赋值而不是构造成员(因为后者在语法上不会有效)。但是要警惕代码重复。另一种方法可能是使用像copy-and-swap这样的习惯用法将工作委托给构造函数:
GameObject &operator=(const GameObject &rhs) {
GameObject tmp(rhs);
tmp.swap(*this);
return *this;
}
另外,正如其他几个人已经注意到的那样,如果你的构造函数和赋值与编译器生成的默认值(就像它们当前那样)相同,那么删除它们会更短更安全,只需使用默认为。