这是一个还过得去的软件设计吗?
我目前正在用 C++ 开发一款游戏。由于没有垃圾收集器,因此必须始终小心地删除对象,并确保这些对象一旦被删除就不会再被访问。
现在,随着项目的发展,一些对象可能会从越来越多的地方被引用。例如,我在游戏中的单位可能会从渲染器、场景层次结构、选择机制、HUD 等中引用。现在 - 如果一个对象被删除,则必须确保引用该对象的所有其他类都将收到通知。
或者换句话说 - 如果我创建一个可能引用我的一个单元的新类,我还必须更改该单元的代码(或单元管理器或任何模块删除该单元的代码,如果它得到) destroy)以确保这个新模块知道它当前引用的特定单元何时被删除。
现在我认为可能有一种简单的事件驱动通用方法通过创建另一个对象可以订阅的基类来解决这个问题。像这样的事情:
class DeletableBase;//forward declaration
class ISubscriber{
public:
virtual someObjectGotDeleted(DeletableBase* deletedObject)=0;
};
class DeletableBase{
private:
vector<ISubscriber*> subscribers;
public:
virtual ~DeletableBase(){
for(int i=0; i<subscribers.size(); i++)
subscribers[i]->someObjectGotDeleted(this);
}
subscribeForDeleteEvent(ISubscriber* subscriber){
subscribers.push_back(subscriber);
}
};
这样 - 如果我从新类引用从该类继承的任何对象,我可以简单地将自己添加为订阅者,如果该对象将从任何其他地方删除,我会收到通知。
这是一种“干净”的编码方式吗?
I'm currently working on a game in c++. since there's no garbage collector one has always to carefully delete the objects and also make sure that such objects are not accessed anymore once they got deleted.
Now as a project grows some objects may get referenced from more and more places. For example my units in the game may get referenced from the renderer, from the scene hierarchy, from the selection mechanism, from the HUD and so on. now - if a object gets deleted one has to make sure that all other classes that reference this object will be notified about it.
Or let's say it the other way arround - if i create a new class that may reference one of my units, i'll also have to change the code of the unit (or of the unit manager or whatever module delets the unit if it gets destroyed) to make sure this new module knows when the particular unit it currently references gets deleted.
Now I thoght there could be a simple event driven general purpose aproach to solve this problem by creating a baseclass to which one another object can subscribe. Something like this:
class DeletableBase;//forward declaration
class ISubscriber{
public:
virtual someObjectGotDeleted(DeletableBase* deletedObject)=0;
};
class DeletableBase{
private:
vector<ISubscriber*> subscribers;
public:
virtual ~DeletableBase(){
for(int i=0; i<subscribers.size(); i++)
subscribers[i]->someObjectGotDeleted(this);
}
subscribeForDeleteEvent(ISubscriber* subscriber){
subscribers.push_back(subscriber);
}
};
with that - if i reference any object that inherits from this class from a new class i can simply add myself as a subscriber and if the object will be deleted from any other place I will get notifed about it.
is this a "clean" way of coding?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果这纯粹是关于内存管理(而不是状态更改),请改用智能指针。从
shared_ptr
开始,然后使用make_shared
/allocate_shared
或boost::intrusive_ptr
(如果速度太慢)进行优化。If this is purely about memory management (rather than state change), use a smart pointer instead. Start with
shared_ptr
, then optimize usingmake_shared
/allocate_shared
orboost::intrusive_ptr
if it's too slow.您必须考虑的一件事(特别是如果您正在编写游戏)是,当您订阅的对象之一在主线程上被删除时,您的游戏很可能会阻塞,直到每个订阅者都完成了正在做的事情删除对象时执行的操作。如果您不小心,这可能会影响游戏性能。
One thing you'll have to consider (especially if you're writing a game) is that when one of your subscribed objects gets deleted on the main thread, your game will most likely block until each of its subscribers is done doing whatever it's going to do upon deletion of the object. That may affect game performance if you're not careful.
您必须避免删除其他对象引用的对象,但反之则不然。 Boost 智能指针 将完成 90% 的工作你。
PS:C++ 有一个垃圾收集器:-)
You have to avoid dropping objects referenced by other objects, but not the other way around. Boost smart pointers will do 90% of the work for you.
P.S.: There is a garbage collector for C++ :-)
恕我直言,您需要实现自己的内存分配器。您可以观察有关实例类型或类的已释放内存,而不是观察每个实例。当然,为此,您的内存分配器应该是可观察的。您可以使用
map
或set
之类的数据结构或其multi
版本来更有效地通知观察者。这意味着,您的内存管理器将是一个中介者,并且也是可观察的。另外,如果这些释放或通知动作是相互独立的,您可以使用命令模式来分离执行和线程上下文。希望这有帮助。
IMHO, you need to implement your own memory allocator. Instead of observing each instance, you may observe released memory for regarding instance type or class. Of course, in order to that, your memory allocator should be observable. You may use
map
orset
like data structure ormulti
versions of them to notify observers more effectively. Which means, your memory manager will be a mediator and also observable.In addition, if these releasing or notifying actions are independent of each other, you may use Command Pattern to separate execution and thread context. Hope this helps.