views:

173

answers:

6
+2  Q: 

RAII for singleton

I have a singleton class, whose instance get initialized at global scope within the class's CPP file:

Singleton* Singleton::uniqueInstance = new Singleton();

Its header file looks like:

class Singleton {
public:
    static Singleton& getInstance() { return *uniqueInstance; }
    static bool destroyInstance() { delete uniqueInstance; }

private:
    //...
    //... typical singleton stuff
    static Singleton* uniqueInstance;
}; // end of class Singleton

I noticed that its destructor dodn't get executed during program termination, thus I added a public static interface Singleton::destroyInstance(), to be manually invoke by client code before the program exits, for instance deletion. This snippet is not the complete code, and assumed that there are other codes that dealing with thread safety issue. In this case, how can I make use of RAII to eliminate the need of introducing such an interface? Thanks for advice.

+3  A: 

The destructor won't be called automatically because the global object is a pointer, not the object itself. If you were to declare the global object like this:

Singleton Singleton::uniqueInstance();

then the destructor would be automatically called. However, you wouldn't be able to control exactly when the constructor and destructor are called (in relation to construction and destruction of other global objects). If this isn't important to you, then you can use the above method.

Greg Hewgill
Hi Greg, I don't quite understand the code. Do you mean to use a regular global object over singleton pattern?
shiouming
Yes, if you would like the object destructor to be called automatically, then you must use a regular global object. Besides, the singleton "pattern" isn't really a pattern, it was mostly just an example of how to write patterns.
Greg Hewgill
Despite his comment, I don't think Greg was talking about a regular global object in his original answer. You can still use this singleton pattern, but just change from using a pointer to using a regular instance of the class.
drspod
A: 

The most common (and often best) variant of a singleton is a "leaking singleton" -- i.e. one that simply makes no attempt at cleaning up the instance. Except under rather unusual circumstances, this isn't really a problem, because only one instance is leaked, and all the time anything else is executing, that instance needs to exist anyway.

If you really feel obliged to clean up the instance, one way that works reasonably well (though it also has some problems) is to use atexit() to register a function that destroys the instance.

Jerry Coffin
Need to flush and close a file writing in destructor. :(atexit()... it makes me recall a tedious issue when read about phoenix singleton. :P
shiouming
A: 

Since you intend to use RAII, I'm presume you wish to destroy the singleton upon exit from a local scope. If so, I wonder why you're using a singleton at all. A singleton, by definition, is supposed to be global, and hence alive throughout the during of the execution. Perhaps a regular, instance-based approach be more suitable for you here.

Frederick
Put it in a different way... I am trying to fix an existing singleton code. Honestly I'm not too sure if RAII can help to solve the above mentioned problem.
shiouming
A: 

For singleton pattern make sure you define private constructor like this to prevent client from creating many objects:

class Singleton {
public:
    static Singleton& getInstance() { 

      if(!uniqueInstance)
         uniqueInstance = new Singleton();

      return *uniqueInstance; 
    }

    static bool destroyInstance() { delete uniqueInstance; }

private:
    Singleton() { }; //  
    static Singleton* uniqueInstance;
};

Singleton* Singleton::uniqueInstance(NULL);
Ashish
+2  A: 

Singleton are easy to create, unless you are in a MultiThreaded environment. If you can, you'll want to make sure that only one thread is trying to create your singleton (and thus destroy it). Once created it may be used by multiple threads at once... though that may not be the best way to deal with this.

Anyway, a very simplistic option is thus:

class MySingleton
{
public:
  static MySingleton& Intance() { static MySingleton M_Instance; return M_Instance; }
private:
  MySingleton() {}
};

It works well as long as you're not using MI and you do not use the singleton during globals destructions. Also it does not work with VC2003 at least (used to instantiate one singleton for each library the method was called....), I don't know with more recent versions, we've stopped compiling on windows altogether a while ago.

Now, if you want to really learn more about Singleton:

  • instanciation and destruction issues
  • lifetime variety
  • threading safety

Alexandrescu concentrated on this for a full chapter in Modern C++ Design, if you don't have access to the book you can still read the code that resulted from the reflexion in Loki.

Also, you might simply use alternative approaches to the design. Singleton may make testing difficult, there have been interesting thoughts about this from the people that support Dependency Injection. Take a peek at Misko Hevery blog entry.

Matthieu M.
you forgot to declare Instance as static member
sellibitze
oops, silly me :x Guess that's why we should try to compile the examples :)
Matthieu M.
Declaring the instance as local static object works on MinGW. :) I do not have VC2003 with me so can't give it a test.
shiouming
A: 

You have two solutions:

Your object can be constructed before the "main"

... then make it a global object:

// header
class Singleton {
public:
   static Singleton& getInstance() ;
   // ...

private:
    //...
}; // end of class

.

// source
Singleton g_singleton ;

Singleton& Singleton::getInstance()
{
    return g_singleton ;
}

As you mentionned "initialized at global scope", I guess this is what you want.

Your object must be constructed after the "main"

... then put it in a smart pointer:

// header
class Singleton {
public:
    static Singleton& getInstance()
    {
        if(uniqueInstance.get() == 0)
        {
           uniqueInstance.reset(new Singleton()) ;
        }

        return *uniqueInstance;
    }

    private:
    //...
    //... typical singleton stuff
    static std::auto_ptr<Singleton> uniqueInstance;
}; // end of class Singleton

.

// source
std::auto_ptr<Singleton> Singleton::uniqueInstance ;

Thus, the instance will be created at first use, and then, be destroyed by the smart pointer's destructor at the end of the execution.

You still have you multithread access problem for creation, though. This is why I prefer the first solution.

paercebal
Smart pointer works too :)
shiouming