【问题标题】:Ownership and how to avoid shared_ptr所有权以及如何避免 shared_ptr
【发布时间】:2012-12-25 03:13:48
【问题描述】:

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

我在很多情况下看到有人说应该避免 shared_ptr 之类的东西(例如here)。因此,我试图在不共享侦听器所有权的情况下找到实现事件管理器的方法。

我想到的一种方法是为侦听器分配唯一的 ID,并将其 ID 注册到事件管理器。然后,监听器负责在事件管理器更新后“询问”事件管理器是否有可用的事件。

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

【问题讨论】:

  • “我在很多情况下看到人们说应该避免 shared_ptr 之类的东西。”小心这种类型的建议。没有上下文是没有意义的。如果您需要指针,一般没有理由避免使用智能指针。

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


【解决方案1】:

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

另一种方法是使用unique_ptr,它在很多方面都是shared_ptr 硬币的另一面。但是根据您对侦听器的建模方式,甚至可以通过简单地将具体的 instances 保存到事件管理器来避免这种情况。如果没有更详细的描述,就不可能说你是否需要指针,但 if 你不需要它们,是的,建议适用:当具体对象需要时不要使用(智能)指针做。

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

【讨论】:

    【解决方案2】:

    shared_ptr 容易被过度使用;例如,通常建议在 SO 上作为含糊不清的指针问题的解决方案。它不能替代好的设计,除非有基于理解正在编写的代码中的对象生命周期问题的设计,否则不应使用它。

    【讨论】:

      【解决方案3】:

      根据个人经验,shared_ptrs 很棒,但有时可能不是适合这项工作的正确工具。如果代码完全在您的控制之下,那么在 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 作为第一个参数传递给方法,或者您依赖于第 3 方库)。您可以从shared_ptr 获取裸指针,但不能保证它指向的内存地址仍然存在,因为引用计数器不会增加。

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

      还有其他形式的智能指针。例如,OpenSceneGraph 有一个ref_ptr,它比shared_ptr 更容易使用。需要注意的是,它指向的所有对象都必须来自Referenced。但是,如果您对此感到满意,我认为发生真正糟糕的事情要困难得多。

      【讨论】:

        【解决方案4】:

        在某些情况下,shared_ptr 过于矫枉过正或没有正确表达所需的语义(例如传递所有权)。

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

        【讨论】:

          【解决方案5】:

          您的案例不适合很好地使用此处描述的auto_ptrhttp://www.gotw.ca/publications/using_auto_ptr_effectively.htm(本周大师«有效使用 auto_ptr)

          据我了解,您构建了一个侦听器,然后将其交给事件管理器。所以事件管理器可以看作是一个“接收器”。

          使用 auto_ptr 技术,您的事件管理器可以干净、安全地完全拥有您提供给他的侦听器。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2010-12-22
            • 2022-01-09
            • 2019-11-19
            • 1970-01-01
            • 2011-05-24
            • 2014-05-27
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多