Sign in to follow this  
Marz87

Pointer Management

Recommended Posts

Hello helpful readers!

I currently have a class, SDLSubSystem, that inherits from two interfaces: IWindowSystem and ITimerSystem. In my game engine, I have a pointer to a timer system and a pointer to a window system. When SDL is configured, both pointers will end up pointing to SDLSubSystem:


if (m_config.compare("SDL") == 0) {
SDLSubSystem *sdlSystem = new SDLSubSystem();
sdlSystem->init();

m_winSystem = sdlSystem;;
m_timerSystem = sdlSystem;
}


The problem comes when the user quits the window and the engine is shutting down. Before I am able to delete either of the pointers, the other one needs to be set to null:


if (m_config.compare("SDL")) {
m_timerSystem = NULL;
delete m_winSystem;
}


My problem is... this solution is horrible because it could escalate and cleanup isn't as nice as I'd like it to be. Here's what I've researched:

- I've read up on the Enginuity Engine's method for memory management but I also read some articles on the problems of reference counting with pointers.
- I also read up on auto_ptr and heard that it will be deprecated soon, so I don't want to use it.
- I can't seem to get the new standard, unique_ptr, to work on Visual Studio 2008 (I assume that's because it's not a standard yet...)

I'd appreciate any help/insight you may have. Thank you :)

Share this post


Link to post
Share on other sites
That's a kind of unclear "ownership" issue.
Your timer and window are "users" of sdl, not the owner. So you should not free sdl via either timer or window.
Instead, you'd better store sdl to an owner, such like sdlSystem, and when cleanup, call,
delete sdlSystem.
And be sure no "users" will use it after the delete. If you can't do that, notify the "users" before the delete.

If you don't mind mess up the ownership, use a shared pointer (shared_ptr from Boost, e.g) and you don't need to worry about freeing the pointer. But I myself will stick to clear ownership way and never want to mess it up.

Share this post


Link to post
Share on other sites
1: You could upgrade to Visual Studio 2010 and use std::shared_ptr which is a rcptr.

2: You can download Boost and use boost::shared_ptr which is virtually identical.

Share this post


Link to post
Share on other sites
Or you could implement simple reference counter on your own inside a SDLSubSystem. After you perform init and assign it to winSystem and timerSystem this counter should equal 2. On deinit you should not call destructor, but rather decrease reference counter (fe. m_timerSystem->Release()). After both timer and win will release this object it will be automatically destroyed.

Share this post


Link to post
Share on other sites
@wqking: I'm not sure I fully understand. I'd like the engine to be configurable. So in one case you could have the m_winSystem pointing to an SFML Window System while the m_soundSystem is pointing to an OpenAL Sound system. However in some cases you may opt to use the same "system" for everything, and that's where it causes problems.

I suppose the way around this is to have the SDLWindowSystem as its own separate class from SDLTimerSystem, but then I think I run into problems with initialization (e.g. who calls SDL_Init and who calls SDL_InitSubSystem). So I decided to lump the entire SDLSubSystem into one class with multiple inheritance.

@Chris_F: Thanks, I'll look into those!

@Pomnico: Thanks! I've seen that idea but was hoping for alternatives.

Share this post


Link to post
Share on other sites
Quote:
Original post by Marz87
@wqking: I'm not sure I fully understand. I'd like the engine to be configurable. So in one case you could have the m_winSystem pointing to an SFML Window System while the m_soundSystem is pointing to an OpenAL Sound system. However in some cases you may opt to use the same "system" for everything, and that's where it causes problems.


I think what he is suggesting is to have a separate piece of code for taking care of specific subsystems implementations and their initialization and destruction. This might handle the mapping via config of functions to subsystems, handing out the appropriate pointers to wherever m_winSystem and m_timerSystem are being used. When it's time to clean up, this "subsystem manager" can stop the subsystems in the correct order, rather than the class which actually uses the subsystems having to worry about it.

Share this post


Link to post
Share on other sites
Quote:
Original post by WavyVirus

I think what he is suggesting is to have a separate piece of code for taking care of specific subsystems implementations and their initialization and destruction. This might handle the mapping via config of functions to subsystems, handing out the appropriate pointers to wherever m_winSystem and m_timerSystem are being used. When it's time to clean up, this "subsystem manager" can stop the subsystems in the correct order, rather than the class which actually uses the subsystems having to worry about it.


Hm, well I certainly like the idea, but I don't think it solves my problem. I'm just reassigning my problem to another class :P

Share this post


Link to post
Share on other sites
Quote:
Original post by WavyVirus
I think what he is suggesting is to have a separate piece of code for taking care of specific subsystems implementations and their initialization and destruction. This might handle the mapping via config of functions to subsystems, handing out the appropriate pointers to wherever m_winSystem and m_timerSystem are being used. When it's time to clean up, this "subsystem manager" can stop the subsystems in the correct order, rather than the class which actually uses the subsystems having to worry about it.


Thanks so much, that saves a lot of my words. :-)

Share this post


Link to post
Share on other sites
Quote:
Original post by Marz87
Hm, well I certainly like the idea, but I don't think it solves my problem. I'm just reassigning my problem to another class :P


That indeed is to solve your problem...
Please re-read mine, WavyVirus, and CzarKirk's replies again.

Share this post


Link to post
Share on other sites
You don't need a "SubsystemManager". In general, any class with the name "Manager" is suspect in its responsibilities.

I believe you should create two classes SDLWindowSystem and SDLTimerSystem, and have them both use a common "SDL" system which tracks SDL initialisation.

class SDL : noncopyable // e.g. boost::noncopyable
{
public:
SDL()
{
if(SDL_Init(...) < 0)
{
throw std::runtime_exception(SDL_GetError());
}
}

~SDL()
{
SDL_Quit();
}
};

class SDLWindowSystem : public IWindowSystem, private noncopyable
{
public:
SDLWindowSystem(shared_ptr<SDL> sdl); // e.g. boost::shared_ptr
private:
shared_ptr<SDL> sdl;
};

class SDLTimerSystem : public ITimerSystem, private noncopyable
{
public:
SDLTimerSystem(shared_ptr<SDL> sdl); // e.g. boost::shared_ptr
private:
shared_ptr<SDL> sdl;
};

int main()
{
shared_ptr<IWindowSystem> window;
shared_ptr<ITimerSystem> timer;

if (m_config.compare("SDL") == 0)
{
shared_ptr<SDL> sdl = make_shared<SDL>();

window.reset(new SDLWindowSystem(sdl));
timer.reset(new SDLTimerSystem(sdl));
}

// Everything cleaned up via RAII
// No need for nebulous "manager" classes.
}

Share this post


Link to post
Share on other sites
Quote:
Original post by rip-off
You don't need a "SubsystemManager". In general, any class with the name "Manager" is suspect in its responsibilities.


I'm not a native English speaker, so maybe I can't find proper word to substitute "Manager", so I used a lot of "Manager".
Any trick to choose the correct name? I always feel headache on that. And I had read some else where in some forum that said "Manager" is not a good word.
Any suggestion?

Share this post


Link to post
Share on other sites
Manager is a perfectly fine work, normally. The problem is not with the word itself, but the kind of vague classes it represents. What is a "SubsystemManager"? What are its responsibilities?

Manager classes often end up doing too much, and the resulting code can be ugly and riddled with poor dependency separation.

In my proposed design, the SDL class (though admittedly artificial), is responsible for initialising and cleaning up SDL. The SDLWindow is responsible for being a Window, and the SDLTimer is responsible for timing. Finally, because the two types are separate and automatically managed, there is no trouble at cleanup time. Everything unwinds naturally.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this