is this a passable software design?
Asked Answered
U

4

5

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?

Unctuous answered 2/2, 2011 at 14:46 Comment(9)
Belongs on codereview.stackexchange.com. However, I do not want to close this as 'Off Topic' either. :/Seniority
I agree; the close screen needs an option to migrate to sites other than the few they have listed. (Off to Meta!)Recha
I would say it belongs to programmers.SE, not codereview. I think that whoever had the brilliant idea of having 4 programming sites (instead of one, which was good and self contained) should be put to shame.Palmer
it belongs to cpp.stackexchange.comMantellone
There's one caveat: if one of the subscribers gets deleted before the Deletable's destructor is called, this code is most likely to crash, unless your Deletable is also a subscriber for the subscribers.Sain
indeed - but this could be solved by removing ISubscriber and moving it's functionality to DeletableBase instead - and upon subscription there will automatically a cross-subscription be established. the only catch is that each implementation of smeObjectGotDeleted will have to call the base implementationUnctuous
@Mat: think cycles of references (and overhead...)Punt
@Nick : It belongs to cpp-design-reviews-withcodeprovided.stackexchange.comPalmer
@Stefano: hahaha, I should have thought of that ;)Mantellone
P
6

If this is purely about memory management (rather than state change), use a smart pointer instead. Start with shared_ptr, then optimize using make_shared/allocate_shared or boost::intrusive_ptr if it's too slow.

Public answered 2/2, 2011 at 14:53 Comment(3)
hm - but if I do that it means that i'll have to check in each module that references the object (through a smartpointer) in each iteration something like if (myObj->isStillAlive()==false) react();Unctuous
@Mat: It seems you always (regardless to design pattern) need to check the validity of the object or pointer in some way. If you have a pointer to object that may be deleted (invalidated) you need to check this before performing any action on the object. If you have a single module that controls object lifetime, you can use weak_ptr when accessing from other modules. However, you need to check someweakptr.lock() result instead of checking isStillAlive()Molest
@Mat: consider using one boost::shared_ptr and several boost::weak_ptr's then.Public
R
1

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.

Recha answered 2/2, 2011 at 14:53 Comment(0)
O
0

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++ :-)

Orangewood answered 2/2, 2011 at 15:4 Comment(2)
what do you mean by your first phrase? i know there are garbage collectors but i'm coding for the iphone and need a high and constant framerateUnctuous
Why not use Objective C, then?Seam
H
0

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 or set like data structure or multi 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.

Hallam answered 2/2, 2011 at 15:27 Comment(2)
you mean something like this? MyMemoryManager::subscribe(this, objectToObserve)Unctuous
@Unctuous I think it is possible if you overload new operator. Also, you may need to overload delete.Hallam

© 2022 - 2024 — McMap. All rights reserved.