Skip to main content
gamedev.net
🔒 Locked

smart pointers and object managers

Started by Vexator 5 replies 1k views
Original Post
Vexator
Vexator
i'm using boost::smart_ptr for all my objects and it works fine so far. but there are objects whose creation, access and deletion i want to control with special managers who hold all these objects - a resource manager that allocates resources, a sound manager that loads and plays sound sources etc. but if i use smart_ptr's for objects controlled by these managers, i cannot control their deletion. so should i just use regular pointers for objects whose creating, access and deletion is taken care of by managers, or is there a safer alternative? i guess this is what weak_ptr is for, but i'm not sure how to use that in such a case. also i'm not sure how to return objects managed by smart_ptr. let's say we have the following ina class definition:
smart_ptr<Object> GetObject()
{
   return m_Object;
}

smart_ptr<Object> m_Object;
is this the right way to return a pointer to m_Object? or should GetObject() return a reference to the smart_ptr?
Wunderwerk Engine is an OpenGL-based, shader-driven, cross-platform game engine. It is targeted at aspiring game designers who have been kept from realizing their ideas due to lacking programming skills.

blog.wunderwerk-engine.com
jochen
jochen
Quote:

is this the right way to return a pointer to m_Object?


Yes it is.


edit: removed "or should GetObject() return a reference to the smart_ptr?" from quote
Why did Doug Gregor create the empty directory?
Sc4Freak
Sc4Freak
The reference count will always be incremented if you return by value.

For example:
const smart_ptr<Object>& obj = GetObject();

If GetObject() returned a const reference, the refcount would not be incremented which this assignment is made. If GetObject() returns a smart_ptr<Object> by value, the refcount will be incremented and the temporary bound to the reference.

Although, I wonder, does this really matter? I don't think there's really any harm in returning a const reference - if the user stores a reference to a member of the class, and the class dies along the way, it's the user's problem.
pauls_1979
pauls_1979
Quote:
if i use smart_ptr's for objects controlled by these managers, i cannot control their deletion


I'm not sure if this is the best approach, but I have created my own smart pointer system that allows managers to handle/intercept object destruction via callbacks. Anyway I'm not very good with written descriptions so here's a bit of pseudo/source code:

template <typename OBJECT> class ManagedObject{     public:          typedef functor<void, TypeList1(Object *)> ZeroRefFunctor;          inline ManagedObject() : refCount(0)          {          }          // N.B. You may want to make these functions protected/private          // but for the sake of readability I've made them public.          inline void AddRef() const          {               ++ m_refCount;          }          inline void RemoveRef() const          {               if(!(-- m_refCount) && m_zeroRefFunctor)               {                    m_zeroRefFunctor((Object *)this);               }          }          void SetZeroRefFunctor(const ZeroRefFunctor &zeroRefFunctor)          {               m_zeroRefFunctor = zeroRefFunctor;          }     private:          int                m_refCount;          ZeroRefFunctor     m_zeroRefFunctor;};template <class OBJECT> class SmartPtr{     public:          inline SmartPtr() : m_pObject(NULL)          {          }          inline SmartPtr(OBJECT *pObject) : m_pObject(NULL)          {               Set(pObject);          }          inline SmartPtr(const SmartPtr &src) : m_pObject(NULL)          {               Set(src.m_pObject);          }          inline ~SmartPtr()          {               Release();          }          inline void Set(OBJECT *pObject)          {               Release();               if(pObject)               {                    pObject->AddRef();               }               m_pObject = pObject;          }          inline void Release()          {               if(m_pObject)               {                    m_pObject->RemoveRef();                    m_pObject = NULL;               }          }          // Cast, copy, dereference operators etc. go here     private:          OBJECT     *m_pObject;};class MyObject : public ManagedObject<MyObject>{};typedef SmartPtr<MyObject> MyObjectPtr;


Like I say I'm not sure if this is the best approach but it works for me, so hopefully it'll help you out too.
_Kami_
_Kami_
maybe weak pointers?
look at http://www.boost.org/doc/libs/1_38_0/libs/smart_ptr/weak_ptr.htm

let the manager class hold a strong pointer (shared_ptr) and other classes hold weak pointers.

when the last strongpointer is removed, the weakpointers will be NULL, instead of a random memory address.

then you can check for NULL when you do stuff with them.

Another solution is to use a signal system when you want classes to release the pointer to your object.
www.ageofconan.com
popsoftheyear
popsoftheyear
Why can't you control deletion? Hypothetical example:
typedef std::tr1::shared_ptr<SoundObject> SoundObjectPtr;typedef std::map<std::string, SoundObjectPtr> SoundMap;SoundMap loadedSounds;// So to loadloadedSounds["Gun Shot"] = SoundObjectPtr(new SoundObject(_T("..\\Media\\GunShot1.ogg")));// To useloadedSounds["Gun Shot"].Play();// To pass to some other functionvoid DoSomeDSP(SoundObjectPtr soundToChange);// and later...DoSomeDSP(loadedSounds["Gun Shot"]);// To deleteloadedSounds.erase("Gun Shot");

And you can of course use std::map::find to see if sounds exist, loading when needed, etc., etc., and all this can be handled inside your sound manager so the user of the class doesn't have to worry about using the map. But all the functionality is pretty much built in. You don't have to worry about managing the pointer, and you can copy it around if you want.

I don't know why you'd get a reference to a shared pointer... the whole point is to keep a reference count so that when it gets destroyed the user isn't in so much trouble. Or pass a weak pointer around if you want to make sure it's invalidated when the owner is deleted. But the reason you would use the shared pointer is to delegate the responsibility of those tasks so you don't have to worry so much about it any more.

Cheers
-Scott
SiS-Shadowman
SiS-Shadowman
Quote:
Original post by Vexator
but if i use smart_ptr's for objects controlled by these managers, i cannot control their deletion.


Of course you can:

Your managers are the owners of the data they hold, so when they decide their data will be released, no other entity whatsoever should decide to use that data again. I can only think of one possible situation where your managers *want* to release their data, which is when it's not used by anything else which is the case when no one uses their data (boost::shared_ptr::unique): In this case you've got full control over deletion, assign an empty shared_ptr to the one your manager holds.

If you really want to force the deletion of your data when other entities still hold on to them (which shouldn't happen), you will need to return weak_ptr's only, as stated before.

But in general the manger only removes data when it is no longer used.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.