Game Development on a New Frontier RSS 2.0
 Tuesday, July 29, 2008
Yes, I'm aware it's been quite a while since my last post.  I've been caught up with moving to a fun new city, working a fantastic new job, and buying a house.

I stumbled across a problem recently at work dealing with singletons and cleaning up resources in C++.  There are two common methods of creating a singleton, the first being not thread-safe:

public class Singleton
{
public:
   static Singleton* getInstance()
   {
      // The following static will be created once per thread!
      static Singleton instance;
      return &instance;
   }

private:
   Singleton() {}
};

The second being (mostly) thread-safe:

public class Singleton
{
public:
   static Singleton* getInstance()
   {
      if (!m_instance)
      {
         m_instance = new Singleton();
      }

      return m_instance;
   }

private:
   static Singleton* m_instance = NULL;
   Singleton() {}
};

This second case provides a thread-friendly method of creating only a single instance of the class.  (There is a small race condition in that the conditional may be entered by one thread, then having another thread get swapped in before the instance is actually created, but the time window for such a race condition is small enough to generally be safe for use.)  However, sharper viewers may have noticed a small problem:  The new'ed instance memory is never freed!  The intertubes are ablaze with debate about this problem.

On the one hand, it seems to be common (and downright sloppy) practice to rely upon the OS to free the memory when the application shuts down.  That's all fine and dandy when you only work on a "modern" OS, but what if you're working on an embedded system?  Or if your singleton is consuming system (or third-party) resources that need to be released?  My take on the issue is that you should always clean up after yourself; don't rely on the OS to pick up your mess.

So, what can we do about it?  Some people suggest creating some sort of dispose method that the programmer is required to call before exiting the program.  While it's a step in the right direction, this is still a bad idea.  For any of you who work with more than a couple of programmers, you know how hard it is to maintain a large code base on such "assumptions" of what you are supposed to do (nevermind the problem of your Singleton class being part of a library that is referenced by third-party applications).  But what can we do about it?

The solution is rather simple.  Make a class to clean up your mess:

private class SingletonCleaner
{
   ~SingletonCleaner()
   {
      Singleton::getInstance()->dispose();
   }
}

public class Singleton
{
friend class SingletonCleaner;
public:
   static Singleton* getInstance()
   {
      if (!m_instance)
      {
         m_instance = new Singleton();
      }

      return m_instance;
   }

private:
   static Singleton* m_instance = NULL;

   Singleton()
   {
      static SingletonCleaner cleaner;
   }

   static void dispose()
   {
      if (m_instance)
      {
         // Clean up any other used resources here as well
         delete m_instance;
         m_instance = NULL;
      }
   }

};

What's going on here?  We're simply creating a static instance of a friendly class in our Singleton constructor.  We don't have to worry about making the cleaner instance thread-safe, as our Singleton will only enter it's constructor once per process.  By making it static, it will survive until the process exits, at which point its own destructor will be called.  This, in turn, will call the private and static dispose() method of Singleton, cleaning up the Singleton instance and freeing any other system resources it may have acquired.  Simple and easy!

Let me hear your thoughts, questions, concerns, and arguments.  I think it's a pretty solid design, quick and easy, and self-maintaining.

(Bear with me if I've made any compiler errors.  I'm writing this up on a system that does not currently have a C++ compiler.)

Cheers!

Devan
Tuesday, July 29, 2008 7:51:06 PM (Pacific Standard Time, UTC-08:00)  #    Comments [0] -
C++
Comments are closed.
Categories
 
 
 
 
 
 
Archive
<January 2009>
SunMonTueWedThuFriSat
28293031123
45678910
11121314151617
18192021222324
25262728293031
1234567
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2009
Devan Stormont
Sign In
Statistics
Total Posts: 10
This Year: 0
This Month: 0
This Week: 0
Comments: 0
Themes
Pick a theme:
All Content © 2009, Devan Stormont
DasBlog theme 'Business' created by Christoph De Baene (delarou)