2013-01-10 121 views
1

我想写一个简单的事件管理器类和听众的游戏引擎。在通常的实现中(即McShaffry),事件管理器注册监听器,原则上将shared_ptr作为私有成员保存到监听器。所有权和如何避免shared_ptr

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

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

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

+10

“我在很多情况下都看到人们说应该避免shared_ptr和类似的东西。”小心这种类型的建议。没有语境就没有意义。一般来说,如果你需要指针,没有理由避免使用智能指针。 – Mat

回答

2

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

另一种方法是使用unique_ptr,它在很多方面都是shared_ptr硬币的另一面。但取决于你如何建模听众,甚至可以通过简单地将具体的实例保存到事件管理器来避免。如果没有更详细的描述,就不可能说你是否需要指针,但是如果不需要它们,则可以使用,是的,建议适用:不要在具体对象执行时使用(智能)指针。最后,如果你的听众是在别处管理所有权的对象,可以考虑简单地使用原始指向那些对象的指针:在这种情况下,事件管理器根本不是对象的所有者 - 既不是唯一也不是共享的所有者。虽然这对我来说是首选方式,但它需要仔细分析听众的生活时间,以确保活动经理不会指向不再存在的听众。

0

在某些情况下,shared_ptr是矫枉过正或不能正确显示所需的语义(例如传递所有权)。

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

1

shared_ptr倾向于过度使用;例如,经常建议将SO作为模糊指针问题的解决方案。它不能替代优秀的设计,除非基于对正在编写的代码中的对象生命周期问题的理解,否则不应使用该设计。

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另一个地方是,如果你需要一个裸指针传递给函数(如果需要这个传递作为第一个参数的方法,你是靠这可能会发生,或在第三方图书馆)。您可以从shared_ptr获得裸指针,但不能保证指向的内存地址仍然存在,因为参考计数器不会增加。

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

还有其他形式的智能指针。例如,OpenSceneGraph有一个ref_ptr,它比shared_ptr更易于使用。一个警告是,它指向的所有对象必须从Referenced下降。但是,如果你没有问题,我认为发生非常糟糕的事情会更困难。

0

那不是你的情况是一个非常适合的一个不错的使用auto_ptr说明如下:http://www.gotw.ca/publications/using_auto_ptr_effectively.htm(一周的大师有效«使用的auto_ptr)

对于我明白了,你建一个监听器,然后给它致活动经理。所以活动经理可以被看作是“水槽”。

使用auto_ptr技术,您的事件管理器可以干净利落地完全控制您给他的监听器。