所有权以及如何避免shared_ptr

时间:2013-01-10 16:42:30

标签: c++ event-handling shared-ptr ownership

我正在尝试为游戏引擎编写一个简单的事件管理器类和监听器。在通常的实现中(即McShaffry),事件管理器会注册侦听器,这些侦听器原则上将shared_ptr作为私有成员保存到侦听器。

在许多情况下,我已经看到人们应该避免使用shared_ptr和喜欢的东西(例如here)。因此,我试图找到实现事件管理器的方法,而不共享监听器的所有权。

我想到的一种方法是为侦听器分配唯一ID,并使用事件管理器注册其ID。然后听众负责在事件管理员更新后“询问”事件管理员,如果他们的ID下有任何事件可用。

我想问一下,在这种情况下是否有更清晰和/或标准的方法来避免共享所有权,但一般情况下也是如此。例如,我对侦听器有同样的问题。侦听器需要存储指向其父节点(或它们正在侦听的对象)的指针,以便在处理事件时可以调用其方法。

5 个答案:

答案 0 :(得分:2)

正如Mat的评论所说,没有理由不使用智能指针一般。也就是说,警告警告确实似乎适用于您的情况:据我所知,您没有共享所有权;事件管理员拥有听众的唯一所有权。因此shared_ptr不合适。

另一种方法是使用unique_ptr,它在许多方面是shared_ptr硬币的另一面。但是,通过简单地将具体的实例保存到事件管理器中,即使可以避免对听众进行建模的方式。如果没有更详细的描述,就不可能说你是否需要指针,但如果你不需要它们,是的,建议适用:当具体对象没有时,不要使用(智能)指针做。

最后,如果您的侦听器是其他地方管理所有权的对象,请考虑使用 raw 指向这些对象的指针:在这种情况下,事件管理器根本不是对象的所有者 - 既不是唯一或共享所有者。虽然这对我来说是首选方式,但需要仔细分析听众的生命周期,以确保事件管理器不会指向不再存在的监听器。

答案 1 :(得分:1)

shared_ptr往往被滥用;例如,通常建议将SO作为模糊指针问题的解决方案。它不能替代好的设计,除非有一个基于理解正在编写的代码中的对象生命周期问题的设计,否则不应该使用它。

答案 2 :(得分:1)

从个人经验来看,shared_ptr很棒,但有时可能不是正确的工具。如果代码完全由您控制,99.9%的时间shared_ptr可能会让您的生活更轻松。你确实需要确保你没有像以下那样思考:

Foo *f = new Foo();
shared_ptr<Foo> fptr(f);
shared_ptr<Foo> fptr2(f);

这将导致f的内存被fptr1fptr2取消分配。相反,你想做类似的事情:

Foo *f = new Foo();
shared_ptr<Foo> fptr(f);
shared_ptr<Foo> fptr2 = fptr;

在第二种情况下,将一个共享指针分配给另一个共享指针将增加引用计数。

另一个可能遇到shared_ptr问题的地方是你需要将一个裸指针传递给一个函数(如果你需要传递 this 作为第一个参数,可能会发生这种情况一个方法,或者你依赖第三方库)。您可以从shared_ptr获取裸指针,但不保证它指向的内存地址仍然存在,因为引用计数器不会递增。

你可以通过保留额外的shared_ptr来解决这个问题,尽管这可能很麻烦。

还有其他形式的智能指针。例如,OpenSceneGraph的ref_ptrshared_ptr更容易使用。需要注意的是,它指向的所有对象必须从Referenced下降。但是,如果你对此感到满意,我认为让非常糟糕的事情发生起来要困难得多。

答案 3 :(得分:0)

在某些情况下shared_ptr过度杀戮或者没有正确显示所需的语义(例如传递所有权)。

您需要做的是查看您的设计并了解您需要的所有权模型。如果您需要/想要共享所有权,那么只需使用shared_ptr对其进行建模即可。如果共享/参考计数的所有权不合适,请使用另一个智能指针。

答案 4 :(得分:0)

你的情况不适合好好利用这里描述的auto_ptrhttp://www.gotw.ca/publications/using_auto_ptr_effectively.htm(本周的大师«有效使用auto_ptr)

根据我的理解,您构建一个侦听器,然后将其提供给事件管理器。因此,事件管理器可以被视为“接收器”。

使用auto_ptr技术,您的事件管理员可以干净安全地获得您给予他的监听器的完全所有权。

相关问题