c ++ 11 - 所有权和吸气剂

cbo*_*boe 13 c++ shared-ptr ownership unique-ptr c++11

我是C++的新手,我在围绕所有权问题上遇到了麻烦,特别是在吸气时.这是一些示例代码:

class GameObject {
public:
  Transform *transform();
private:
  Transform _transform;
};
Run Code Online (Sandbox Code Playgroud)

我猜一个原始指针是不安全的,因为有人可以在以后不再存在该对象时访问它?

  1. 所以我考虑使用unique_ptr作为转换成员,因为GameObject是唯一拥有转换的人.但是我不能从吸气器那里回来,是吗?但话又说回来,为什么我会首先使用unique_ptr而不是像上面那样添加它?

  2. 那么为什么不使用shared_ptr呢?这对我来说似乎不对,我不想分享所有权,GameObject是所有者,其他人可能会访问它...

  3. 那是什么?参考?我认为shared_ptr似乎是最明智的选择,因为其他人可以安全地保留对变换的引用,但是如果封闭的GameObject被破坏,那么变换是无用的呢?我可能只是想在这里以错误的方式考虑所有权,但每一种方式对我来说都是错误的.谢谢你的帮助.

CB *_*ley 18

很明显(或者应该是显而易见的)阅读你的班级定义的人GameObject拥有一个transform.你是对的,"共享所有权"并不是暗示或期望的.由于不可能无法transform从a中获取a ,GameObject因此不需要像指针(raw或其他)那样表达可能的null的东西,因此返回引用(可能)const似乎是最惯用的事情.

你说原始指针是不安全的,但它并不比任何其他直接访问方法更不安全.以任何方式提供对拥有的转换对象(而不是它的副本)的访问权限,使客户端有机会获取其地址并将其存储在拥有的生命周期之外GameObject.客户不应该做蠢事.没有办法绝对防止这种情况,所以你应该让你的界面简单明了,很难无意中使用不当.


And*_*owl 15

我认为重要的是你的设计模拟了Transform对象归其所有这一事实GameObject.

如果不打算共享所有权(换句话说,如果Transform对象的生命周期严格受限于该生命周期的生命周期GameObject),那么我会避免shared_ptr.

在我看来,你的第一个选择应该是你实际选择的那个:只有一个类型的子对象Transform.但是,返回对它的引用而不是原始指针:

class GameObject {
public:
    Transform& transform();
private:
    Transform _transform;
};
Run Code Online (Sandbox Code Playgroud)

这是传达这样一个事实的最清晰的方式:您提供对子对象的访问权限,但给予_transform对象权限.

客户不必担心诸如" 我何时以及如何删除此对象?我应该删除它吗? "这样的问题,因为您的界面很明确:没有所有权,没有责任.

另一方面,有理由可能会阻止您这样做.一个可能的原因可能是a GameObject可能拥有也可能不拥有Transform对象.如果是这种情况,您可能希望使用unique_ptr(而返回原始指针,可能为null).

使用a的另一个原因unique_ptr可能是Transform子对象的构造需要延迟,因为构造函数接受一些需要计算的值,并且无法在构造函数的初始化列表中提供.

一般来说,除非你有充分的理由这样做,否则最喜欢最简单的解决方案,只需嵌入一个类型的子对象Transform,给出一个参考.


Bal*_*Pal 5

经验法则:只有当它完全无法避免时,你才会对指针和所有权感到烦恼.C++具有良好的价值语义(使用const ref扩展),所以你可以在想要指针,聪明或愚蠢之前走得很远.

在你的例子中,_transform作为直接成员非常好.如果你想要一个吸气剂,你可以做到

Transform transform() const {return _transform; }
Run Code Online (Sandbox Code Playgroud)

在某些特殊情况下可能会

const Transform& transform() const {return _transform; }
Run Code Online (Sandbox Code Playgroud)

有生命的文件.只有在合理的情况下才这样做.

嗯,显然,吸气剂的最佳方法是根本没有它们.面向对象是关于行为,让你的类做你的工作,而不是使用它作为你从外面戳戳和查询的数据转储.