Jump to content

Singletons - The Next Generation: Difference between revisions

From EDM2
Prokushev (talk | contribs)
No edit summary
 
Ak120 (talk | contribs)
mNo edit summary
 
(4 intermediate revisions by 2 users not shown)
Line 1: Line 1:
Written by [[Stefan Ruck]]
''Written by [[Stefan Ruck]]''


 
In December 1997 I introduced my version of the Singleton template class in EDM/2 [1]. Now, some time has gone by and Anapum Kapoor and Ittay Freiman inspired me to rethink the design.  
<p>
If you haven't done so yet, please read my [http://www.edm2.com/0512/singleton.html original article] first to be able
In December 1997 I introduced my version of the Singleton template class in
EDM/2 [1]. Now, some time has gone by and Anapum Kapoor and Ittay Freiman inspired me  
to rethink the design.  
If you haven't done so yet, please read  
my <a HREF="../../0512/singleton.html">original article</a> first to be able
to understand all the points I discuss here.
to understand all the points I discuss here.


==Another Approach - (Nearly) The Same Result==
As promised in the first Singleton article, I will first show you another way to attain nearly the same result. Why I say 'nearly' will be explained shortly.


<h3>Another Approach - (Nearly) The Same Result</h3>
Björn Fahller, another EDM/2 author, was the first who showed me a different way to achieve the goals of a singleton. And since I feel he provided a really good explanation, I will just quote his mail. From now on, I will refer to this
implementation as the 'static singleton'. Here is what Björn wrote:


<p>
As promised in the first Singleton article, I will first show you another way
to attain nearly the same result. Why I say 'nearly' will be explained shortly.
<p>
Bj&ouml;rn Fahller, another EDM/2 author, was the first who showed me a different
way to achieve the goals of a singleton. And since I feel he provided a really
good explanation, I will just quote his mail. From now on, I will refer to this
implementation as the 'static singleton'. Here is what Bj&ouml;rn wrote:
<p>
<i>
The way out is totally different:
The way out is totally different:
<p>
<pre>
<pre>
class X // our singleton class
class X // our singleton class
Line 42: Line 26:
   return x;
   return x;
}
}
</pre>
<p>
</i>
Figure 1: Static Singleton
<i>
<p>
Whenever you need your singleton in your code, call
<pre>
X::instance().someMethod();
</pre>
</pre>
''Figure 1: Static Singleton''


<p>
Whenever you need your singleton in your code, call:
Sure, different syntax, but the meaning is the same, and it's safe from
X::instance().someMethod();
the semantic drawbacks (it'll even be destroyed.) It has one potential
real drawback, though. The object is constructed the first time used,
which makes it very improper for real-time systems (you never know which
call will create it, and thus cannot know how long a call will take).
</i>
 
<p>
That's what Bj&ouml;rn wrote. Now you might ask what's the difference besides
having less code (no reference counting is needed and no template class).
There are two. First, the static singleton is located in the program's static
storage, while mine is put on the heap since it is created by calling
the <code>new</code> constructor. Secondly, once a static singleton is created, it
can't be destroyed. My implementation destroys the singleton as soon as the
reference counter reaches zero, in other words, once the singleton is no longer
needed. This is a very important fact to remember for later on.


<p>
Sure, different syntax, but the meaning is the same, and it's safe from the semantic drawbacks (it'll even be destroyed.) It has one potential real drawback, though. The object is constructed the first time used, which makes it very improper for real-time systems (you never know which call will create it, and thus cannot know how long a call will take).
But if you do not need or want to destroy and recreate a singleton at
runtime, I think the static singleton is the way to go.


<h3>The (Temporary) Singleton Implementation Class</h3>
That's what Björn wrote. Now you might ask what's the difference besides having less code (no reference counting is needed and no template class).
There are two. First, the static singleton is located in the program's static storage, while mine is put on the heap since it is created by calling the <tt>new</tt> constructor. Secondly, once a static singleton is created, it can't be destroyed. My implementation destroys the singleton as soon as the reference counter reaches zero, in other words, once the singleton is no longer eeded. This is a very important fact to remember for later on.


<p>
But if you do not need or want to destroy and recreate a singleton at runtime, I think the static singleton is the way to go.
Writing sample code for this article, I first decided to create a little
helper to avoid having to recode a few methods for each singleton class.


<p>
==The (Temporary) Singleton Implementation Class==
Looking at the sample code in [1], you might notice it's necessary to
Writing sample code for this article, I first decided to create a little helper to avoid having to recode a few methods for each singleton class.
implement the static data members m_ulReferenceCounter, m_pInstance and the
static methods instance() and releaseInstance() for each class that should
be used as a singleton. Of course, copy and paste goes very fast, but there
are ways in C++ to avoid this.


<p>
Looking at the sample code in [1], you might notice it's necessary to implement the static data members m_ulReferenceCounter, m_pInstance and the static methods instance() and releaseInstance() for each class that should be used as a singleton. Of course, copy and paste goes very fast, but there are ways in C++ to avoid this.
First, you might ask why not creating a base class which implements these four
members. This is not desirable for two reasons. First, you might need
multiple inheritance which is not allowed in all organizations (for whatever
reasons). Secondly, the base class can only handle a pointer
of its own type, not of the final singleton class, since we can't know each
derived class will ever be created when defining it. So this is not the
solution.


First, you might ask why not creating a base class which implements these four members. This is not desirable for two reasons. First, you might need multiple inheritance which is not allowed in all organizations (for whatever reasons). Secondly, the base class can only handle a pointer of its own type, not of the final singleton class, since we can't know each
derived class will ever be created when defining it. So this is not the solution.


<p>
What can we do? Reading a little bit about Microsoft's ATL gave me the final idea. A client of a singleton based on my ASingletonST class can only call its public members. Also, a default constructor is necessary to clearly initialize the object without having to use any sort of initialization method. So why not have a class that uses the singleton class as its base class? implements the singleton specific members and is the one used by ASingletonST. This can easily be done by using
What can we do? Reading a little bit about Microsoft's ATL gave me the final
idea. A client of a singleton based on my ASingletonST class can only
call its public members. Also, a default constructor is necessary  
to clearly initialize the object without having to use any sort of
initialization method. So why not have a class that uses
the singleton class as its base class? implements the singleton specific members
and is the one used by ASingletonST. This can easily be done by using
a template class. Here is the declaration:
a template class. Here is the declaration:
 
<pre>
<p>
template <class T>
<font COLOR="#0000BB"><pre>
template &lt;class T&gt;
class ASingletonImpl : public T
class ASingletonImpl : public T
{
{
Line 119: Line 56:
     // number of users
     // number of users
     static unsigned long referenceCounter ()
     static unsigned long referenceCounter ()
       { return (ASingletonImpl &lt;T&gt; :: m_ulReferenceCounter); }
       { return (ASingletonImpl <T> :: m_ulReferenceCounter); }


   protected:
   protected:
Line 126: Line 63:
  private:
  private:
     // not implemented
     // not implemented
     ASingletonImpl (const ASingletonImpl &lt;T&gt; & rSource);
     ASingletonImpl (const ASingletonImpl <T> & rSource);


     // not implemented
     // not implemented
     ASingletonImpl &lt;T&gt; & operator = (const ASingletonImpl &lt;T&gt; & rSource);
     ASingletonImpl <T> & operator = (const ASingletonImpl <T> & rSource);


     // return the instance
     // return the instance
     static ASingletonImpl &lt;T&gt; * instance ();
     static ASingletonImpl <T> * instance ();


     // release the instance
     // release the instance
Line 138: Line 75:


     // pointer to the single instance
     // pointer to the single instance
     static ASingletonImpl &lt;T&gt; * m_pInstance;
     static ASingletonImpl <T> * m_pInstance;


     // counts the instance requests
     // counts the instance requests
     static unsigned long m_ulReferenceCounter;
     static unsigned long m_ulReferenceCounter;


     friend class ASingletonST &lt;T&gt;;
     friend class ASingletonST <T>;
};
};
</pre>
''Figure 2: The Singleton Implementation Class''


</pre></font>
<p>
Figure 2: The Singleton Implementation Class
<p>
The implementation of the class looks like this:
The implementation of the class looks like this:
 
<pre>
<font COLOR="#0000BB"><pre>
// initialize the pointer
// initialize the pointer
template &lt;class T&gt;
template <class T>;
ASingletonImpl &lt;T&gt; * ASingletonImpl &lt;T&gt; :: m_pInstance = 0L;
ASingletonImpl <T> * ASingletonImpl <T> :: m_pInstance = 0L;


// initialize the counter
// initialize the counter
template &lt;class T&gt;
template <class T>


unsigned long ASingletonImpl &lt;T&gt; :: m_ulReferenceCounter = 0L;
unsigned long ASingletonImpl <T> :: m_ulReferenceCounter = 0L;


//****************************************************************
//****************************************************************
Line 168: Line 100:
//****************************************************************
//****************************************************************


template &lt;class T&gt;
template <class T>
ASingletonImpl &lt;T&gt; * ASingletonImpl &lt;T&gt; :: instance ()
ASingletonImpl <T> * ASingletonImpl <T> :: instance ()


{
{
Line 175: Line 107:
   if (!m_pInstance)
   if (!m_pInstance)
       // no, allocate it
       // no, allocate it
       m_pInstance = new ASingletonImpl &lt;T&gt;;
       m_pInstance = new ASingletonImpl <T>;


   // increase the counter
   // increase the counter
Line 188: Line 120:
//***********************************************************
//***********************************************************


template &lt;class T&gt;
template <class T>


void ASingletonImpl &lt;T&gt; :: releaseInstance ()
void ASingletonImpl <T> :: releaseInstance ()


{
{
   if (!m_ulReferenceCounter)  // no instance allocated?
   if (!m_ulReferenceCounter)  // no instance allocated?
       return;                // yes, return
       return;                // yes, return
   // decrease the number of active users
   // decrease the number of active users
   --m_ulReferenceCounter;
   --m_ulReferenceCounter;
   // is the instance still in use?
   // is the instance still in use?
   if (m_ulReferenceCounter)
   if (m_ulReferenceCounter)
       return;                // yes, return
       return;                // yes, return
   delete m_pInstance;        // delete the instance
   delete m_pInstance;        // delete the instance
   m_pInstance = 0L;          // reset the pointer
   m_pInstance = 0L;          // reset the pointer
}
}
</pre></font>
</pre>
''Figure 3: Implementation of the Singleton Implementation Class''


<p>
Comparing this to the implementation of the sample code in [1], you will notice two differences. The somewhat cryptic declaration of the static data members and the allocation of an object of type ASingletonImpl <T> instead
Figure 3: Implementation of the Singleton Implementation Class
of the singleton class itself in the instance() method. The rest has been left unchanged.


<p>
==The Drawbacks==
Comparing this to the implementation of the sample code in [1], you will
I used IBM's VisualAge 4.0 compiler to implement the sample code with ASingletonImpl and a modified version of ASingletonST. This compiler has one big advantage against any other compiler I know: you don't need to worry about <code>#include</code> statements in any file. Just put all the ''includes'' you need into the project's configuration file and the compiler will
notice two differences. The somewhat cryptic declaration of the static data
members and the allocation of an object of type ASingletonImpl &lt;T&gt; instead
of the singleton class itself in the instance() method. The rest has been left
unchanged.
 
<h3>The Drawbacks</h3>
 
<p>
 
I used IBM's VisualAge 4.0 compiler to implement the sample code
with ASingletonImpl and a modified version of ASingletonST. This compiler
has one big advantage against any other compiler I know: you don't
need to worry about <code>#include</code> statements in any file. Just put all the
<i>includes</i> you need into the project's configuration file and the compiler will
do the job.
do the job.


<p>
Trying to use these classes at work with Microsoft's VC++ 6.0 I ran into unresolvable problems because of cross-references between ASingletonST and ASingletonImpl. The result was I couldn't use the classes.
Trying to use these classes at work with Microsoft's VC++ 6.0
I ran into unresolvable problems because of cross-references between
ASingletonST and ASingletonImpl. The result was I couldn't use the classes.


<h3>The Next ASingletonST Generation</h3>
==The Next ASingletonST Generation==
 
Thinking about it a bit, I asked myself why not combine the advantages of ASingletonImpl with ASingletonST. No sooner thought than done. ASingletonST got a new interface and implementation.
<p>
<pre>
Thinking about it a bit, I asked myself why not combine the advantages
template <class T>
of ASingletonImpl with ASingletonST. No sooner thought than done. ASingletonST got a new
interface and implementation.
 
<p>
<font COLOR="#0000BB"><pre>
template &lt;class T&gt;


class ASingletonST
class ASingletonST
Line 261: Line 167:
   private:
   private:
     // not implemented
     // not implemented
     ASingletonST (const ASingletonST &lt;T&gt; & rSource);
     ASingletonST (const ASingletonST <T> & rSource);
     // not implemented
     // not implemented
     ASingletonST &lt;T&gt; & operator = (const ASingletonST &lt;T&gt; & rSource);
     ASingletonST <T> & operator = (const ASingletonST <T> & rSource);


     // create the instance and/or increment refcount
     // create the instance and/or increment refcount
Line 277: Line 183:
     static unsigned long m_ulReferenceCounter;
     static unsigned long m_ulReferenceCounter;
};
};
</pre></font>
</pre>
 
''Figure 4: ASingletonST's New Interface''
<p>
Figure 4: ASingletonST's New Interface


<p>
The new implementation of ASingletonST looks like this.
The new implementation of ASingletonST looks like this.
 
<pre>
<font COLOR="#0000BB"><pre>
// define and initialize the pointer
// define and initialize the pointer
template &lt;class T&gt;
template <class T>
T * ASingletonST &lt;T&gt; :: m_pInstance = 0L;
T * ASingletonST <T> :: m_pInstance = 0L;


// define and initialize the counter
// define and initialize the counter
template &lt;class T&gt;
template <class T>
unsigned long ASingletonST &lt;T&gt; :: m_ulReferenceCounter = 0L;
unsigned long ASingletonST <T> :: m_ulReferenceCounter = 0L;


//*****************************************************************
//*****************************************************************
Line 298: Line 200:
//*****************************************************************
//*****************************************************************


template &lt;class T&gt;
template <class T>
T * ASingletonST &lt;T&gt; :: operator -> ()
T * ASingletonST <T> :: operator -> ()
{
{
   if (!m_pInstance)
   if (!m_pInstance)
Line 311: Line 213:
//******************************************************************
//******************************************************************


template &lt;class T&gt;
template <class T>


T & ASingletonST &lt;T&gt; :: operator * ()
T & ASingletonST <T> :: operator * ()
{
{
   if (!m_pInstance)
   if (!m_pInstance)
Line 325: Line 227:
//********************************************************
//********************************************************


template &lt;class T&gt;
template <class T>
void ASingletonST &lt;T&gt; :: instance ()
void ASingletonST <T> :: instance ()
{
{
   // do we have an instance already?
   // do we have an instance already?
Line 341: Line 243:
//***********************************************************
//***********************************************************


template &lt;class T&gt;
template <class T>
void ASingletonST &lt;T&gt; :: releaseInstance ()
void ASingletonST <T> :: releaseInstance ()
{
{
   if (!m_ulReferenceCounter)  // no instance allocated?
   if (!m_ulReferenceCounter)  // no instance allocated?
Line 358: Line 260:
   m_pInstance = 0L;          // reset the pointer
   m_pInstance = 0L;          // reset the pointer
}
}
</pre>
''Figure 5: Implementation of the new ASingletonST Class''


</pre></font>
To avoid any complications, I've made the copy constructor and assignment operator private and didn't implemented them. Since I know now that an explicit call of the destructor is possible [2], I've expanded the members for security reasons. Using this version, it is safe (but not desirable) e.g. to call ASingletonST's destructor and afterwards the -> operator.
<p>
Figure 5: Implementation of the new ASingletonST Class
 
<p>
To avoid any complications, I've made the copy constructor and assignment
operator private and didn't implemented them. Since I know now that an
explicit call of the destructor is possible [2], I've expanded the members for
security reasons. Using this version, it is safe (but not desirable) e.g. to
call ASingletonST's destructor and afterwards the -> operator.
 
<p>
Implementing a 'real' singleton class using ASingletonST requires only two things:
be sure to declare operator= and all constructors as private and make
ASingletonST&lt;class&gt; a friend of it.
 
<p>
But ASingletonST also gives you the ability to use any class as a singleton.
One thing about classes not designed as singletons is that you
can't prevent them from not being used by others as a singleton.


<h3>The Singleton Manager Design Pattern</h3>
Implementing a 'real' singleton class using ASingletonST requires only two things: be sure to declare operator= and all constructors as private and make ASingletonST<class> a friend of it.


<p>
But ASingletonST also gives you the ability to use any class as a singleton. One thing about classes not designed as singletons is that you can't prevent them from not being used by others as a singleton.
Ittay Freiman was the first who introduced the idea of a 'singleton manager'
since he had the problem of using singletons depending on each other and so
needed something that controls the sequence of their construction and destruction.


==The Singleton Manager Design Pattern==
Ittay Freiman was the first who introduced the idea of a 'singleton manager' since he had the problem of using singletons depending on each other and so needed something that controls the sequence of their construction and destruction.


<p>
Using a static singleton makes it impossible to exercise control over the sequence since the sequence in which local static objects are destroyed is not defined (see C++ Reference Manual [3]).
Using a static singleton makes it impossible to exercise control over the
sequence since the sequence in which local static objects are destroyed is not
defined (see C++ Reference Manual [3]).


<p>
So my solution of using pointers and reference counting is needed.
So my solution of using pointers and reference counting is needed.


<p>
The singleton manager's task is to take control over the sequence of creation and destruction of singletons that depend on each other.
The singleton manager's task is to take control over the sequence of creation
and destruction of singletons that depend on each other.


<p>
Therefore, it needs to be created before any client might need any singleton and should be destroyed only when no one needs any more singletons.
Therefore, it needs to be created before any client might need any singleton
and should be destroyed only when no one needs any more singletons.


<p>
One thing really helpful here is the definition of when the constructors and destructors of data members are called. The Standard says "First, the base classes are initialized in declaration order ..., then the members are initialized in
One thing really helpful here is the definition of when the constructors and
declaration order (independent of the order of mem-initializers)... The declaration order is used to ensure that ... members are destroyed in the reverse order of initialization." [4].
destructors of data members are called. The Standard says "First, the base classes are
initialized in declaration order ..., then the members are initialized in
declaration order (independent of the order of mem-initializers)... The
declaration order is used to ensure that ... members are destroyed in the
reverse order of initialization." [4].


<p>
With this in mind, it's quite easy to create a singleton manager that ensures the right sequence of singleton creation and destruction. Just declare a data member for each singleton needed in the right sequence: independent singletons first, dependent ones later.
With this in mind, it's quite easy to create a singleton manager that
ensures the right sequence of singleton creation and destruction.
Just declare a data member for each singleton needed in the right sequence:
independent singletons first, dependent ones later.


<p>
If, for whatever reason, you need a different order of destruction, you might call the destructor of the data members inside the manager's destructor in the sequence you need. This is why I check for a valid instance in ASingletonST::operator-> and ASingletonST::operator*. You can (but I think should not) call the destructor of a class whenver you like.
If, for whatever reason, you need a different order of destruction, you might
call the destructor of the data members inside the manager's destructor
in the sequence you need. This is why I check for a valid instance
in ASingletonST::operator-> and ASingletonST::operator*. You can (but I think
should not) call the destructor of a class whenver you like.


<h3>A First Attempt</h3>
==A First Attempt==
 
To fulfil the tasks described above, you might create a singleton manager which looks like this:
<p>
<pre>
To fulfil the tasks described above, you might create a singleton manager
which looks like this:
 
<p>
<font COLOR="#0000BB"><pre>
class ASingletonManager
class ASingletonManager
{
{
Line 439: Line 296:
//whatever
//whatever
private:
private:
   ASingletonST&lt;class1&gt; m_Class1;
   ASingletonST<class1> m_Class1;
   ASingletonST&lt;class2&gt; m_Class2;
   ASingletonST<class2> m_Class2;
   ASingletonST&lt;class3&gt; m_Class3;
   ASingletonST<class3> m_Class3;
}
}
</pre></font>
</pre>
<p>
''Figure 6: A Singleton Manager''
Figure 6: A Singleton Manager


 
And to alter the singleton destruction sequence from the default, you could code the destructor like this:
<p>
<pre>
And to alter the singleton destruction sequence from the default,
you could code the destructor like this:
<p>
<font COLOR="#0000BB"><pre>
ASingletonManager::~ASingletonManager()
ASingletonManager::~ASingletonManager()
{
{
   m_Class1.ASingletonST&lt;class1&gt;::~ASingletonST();
   m_Class1.ASingletonST<class1>::~ASingletonST();
 
   m_Class3.ASingletonST<class3>::~ASingletonST();
   m_Class3.ASingletonST&lt;class3&gt;::~ASingletonST();
   m_Class2.ASingletonST<class2>::~ASingletonST();
 
   m_Class2.ASingletonST&lt;class2&gt;::~ASingletonST();
}
}
</pre></font>
</pre>
<p>
''Figure 7: Example of Controlling the Sequence of Destruction''
Figure 7: Example of Controlling the Sequence of Destruction


<p>
In this sample, m_Class1 will be initialized first, then m_Class2 and lastly m_Class3. Assuming there is no other client currently using one of the singletons, in ASingletonManager::~ASingletonManager() the class1 singleton will be destroyed first, then class3 and finally class2. The order without an explicit call to ASingletonST<>::~ASingletonST() would be class3 first, class2 second and class1 third.
In this sample, m_Class1 will be initialized first, then m_Class2 and lastly
m_Class3. Assuming there is no other client currently using one of the
singletons, in ASingletonManager::~ASingletonManager() the class1 singleton
will be destroyed first, then class3 and finally class2. The order without
an explicit call to ASingletonST<>::~ASingletonST() would be class3 first,
class2 second and class1 third.


But this example conflicts with the ANSI/ISO standard which says "A destructor may not be invoked more than once for an object"[5]. Here, it will be called twice: first explicit by the manager's destructor, and later implicitly when ASingletonManager's data members are destroyed.


<p>
To be completely free of any declaration order, you need to implement the ASingletonST members of the manager as pointers, which will be allocated by the constructor, independent of the order in which the pointer members are declared.
But this example conflicts with the ANSI/ISO standard which says "A
<pre>
destructor may not be invoked more than once for an object"[5]. Here, it
will be called twice: first explicit by the manager's destructor, and
later implicitly when ASingletonManager's data members are destroyed.
 
<p>
To be completely free of any declaration order, you need to implement
the ASingletonST members of the manager as pointers, which will be allocated
by the constructor, independent of the order in which the pointer members
are declared.
 
<p>
<font COLOR="#0000BB"><pre>
class ASingletonManager
class ASingletonManager
{
{
Line 495: Line 327:
//whatever
//whatever
private:
private:
   ASingletonST&lt;class1&gt; * m_pClass1;
   ASingletonST<class1> * m_pClass1;
   ASingletonST&lt;class2&gt; * m_pClass2;
   ASingletonST<class2> * m_pClass2;
   ASingletonST&lt;class3&gt; * m_pClass3;
   ASingletonST<class3> * m_pClass3;
}
}


Line 505: Line 337:
                       m_pCLass3 (0L)
                       m_pCLass3 (0L)
{
{
   m_pClass2 = new ASingletonST&lt;class2&gt;;
   m_pClass2 = new ASingletonST<class2>;
 
   m_pClass3 = new ASingletonST<class3>;
   m_pClass3 = new ASingletonST&lt;class3&gt;;
   m_pClass1 = new ASingletonST<class1>;
 
   m_pClass1 = new ASingletonST&lt;class1&gt;;
}
}


Line 515: Line 345:
{
{
   delete m_pClass3;
   delete m_pClass3;
   delete m_pClass1;
   delete m_pClass1;
   delete m_pClass2;
   delete m_pClass2;
}
}
</pre>
''Figure 8: Using Pointers to ASingletonST''


</pre></font>
Any time the program needs an instance of the singleton, an object of ASingletonST<class> can be created and used. The instance returned by this object is the one created by the singleton manager. But remember to make sure a manager is created before any user creates an ASingletonST<> object that refers to a singleton handled by the singleton manager. And the manager must stay alive until no more managed singletons are needed.
<p>
Figure 8: Using Pointers to ASingletonST


<p>
==Another (Better) Way==
Any time the program needs an instance of the singleton, an object of
Implementing a singleton manager as described above, you have to take care that the singleton manager is the first to reference the singleton and the last to free the reference.
ASingletonST&lt;class&gt; can be created and used. The instance returned by this
object is the one created by the singleton manager. But remember to make sure
a manager is created before any user creates an ASingletonST&lt;&gt; object that
refers to a singleton handled by the singleton manager. And the manager must
stay alive until no more managed singletons are needed.


<h3>Another (Better) Way</h3>
To eliminate this disadvantage, some changes are needed. We have to make sure that no client can create a singleton without using the singleton manager.


<p>
So first declare the constructors of any class which should have only one instance as private and make the singleton manager a friend class. Second, implement the manager itself as a singleton. Third, implement a public interface to access the 'one-instance' members.
Implementing a singleton manager as described above, you have to take care
that the singleton manager is the first to reference the singleton and
the last to free the reference.


<p>
The 'one-instance' classes don't need to be designed as singletons any more since no one but the singleton manager can create an object of that class. Only the manager must be a singleton. Now any client that needs access to the 'one-instance' objects first needs to create an object of ASingletonST<SingletonManager> which guarantees the right construction and destruction order of the 'one-instance' objects. The 'one-instance' objects can only be accessed through the singleton manager's interface.
To eliminate this disadvantage, some changes are needed. We have to make sure
that no client can create a singleton without using the singleton
manager.


<p>
So first declare the constructors of any class which should have only one
instance as private and make the singleton manager a friend class. Second,
implement the manager itself as a singleton. Third, implement a public
interface to access the 'one-instance' members.
<p>
The 'one-instance' classes don't need to be designed as singletons any more
since no one but the singleton manager can create an object of that
class. Only the manager must be a singleton. Now any client that needs access
to the 'one-instance' objects first needs to create an object of
ASingletonST&lt;SingletonManager&gt; which guarantees the right construction and
destruction order of the 'one-instance' objects. The 'one-instance' objects
can only be accessed through the singleton manager's interface.
<p>
The sample code below shows how to do it, using the new ASingletonST class.
The sample code below shows how to do it, using the new ASingletonST class.
<p>
<pre>
<font COLOR="#0000BB"><pre>
class A
class A
{
{
Line 622: Line 421:
   BDependsOnA m_BDependsOnA;
   BDependsOnA m_BDependsOnA;


   friend class ASingletonST&lt;ASingletonManager&gt;;
   friend class ASingletonST<ASingletonManager>;
};
};


Line 628: Line 427:
{
{
         cout << "f2" << endl;
         cout << "f2" << endl;
         ASingletonST<ASingletonManager> pSingletonManager;
         ASingletonST<ASingletonManager> pSingletonManager;
         pSingletonManager->bDependsOnA().text();
         pSingletonManager->bDependsOnA().text();
         pSingletonManager->a().text();
         pSingletonManager->a().text();
}
}
Line 639: Line 435:
{
{
         cout << "f1" << endl;
         cout << "f1" << endl;
         ASingletonST<ASingletonManager> pSingletonManager;
         ASingletonST<ASingletonManager> pSingletonManager;
         pSingletonManager->a().text();
         pSingletonManager->a().text();
         f2();
         f2();
         pSingletonManager->bDependsOnA().text();
         pSingletonManager->bDependsOnA().text();
}
}
Line 653: Line 445:
         f1();
         f1();
}
}
</pre>
''Figure 9: Example of Using the Singleton Manager''


</pre></font>
<p>
Figure 9: Example of Using the Singleton Manager
<p>
The output of the sample code is this:
The output of the sample code is this:
<font COLOR="#0000BB"><pre>
<pre>
f1
f1
A::A
A::A
Line 673: Line 462:
BDependsOnA::~BDependsOnA
BDependsOnA::~BDependsOnA
A::~A
A::~A
</pre></font>
</pre>
<p>
''Figure 10: Sample Code Output''
Figure 10: Sample Code Output
 
<p>
You might wonder why A::A and BDependsOnA::BDependsOnA is printed out before
ASingletonManager::ASingletonManager. The answer is that the constructors of
A and BDependsOnA are called during member initialization which occurs before
the ASingletonManager::ASingletonManager code is executed.
 
<h3>Conclusion</h3>


<p>
You might wonder why A::A and BDependsOnA::BDependsOnA is printed out before ASingletonManager::ASingletonManager. The answer is that the constructors of A and BDependsOnA are called during member initialization which occurs before the ASingletonManager::ASingletonManager code is executed.
I think it's much easier now to create singletons using the new ASingletonST
template class. It saves you from having to code singleton implementation details
over and over again, lets you put the focus on the singleton classes and allows
you to use classes never meant to be singletons as singletons.


==Conclusion==
I think it's much easier now to create singletons using the new ASingletonST template class. It saves you from having to code singleton implementation details over and over again, lets you put the focus on the singleton classes and allows you to use classes never meant to be singletons as singletons.


<p>
The Singleton Manager Design Pattern is one thing I really like. I've been using it since the days I first designed it in a commercial real-world program and it works fine. I hope you enjoy it too!
The Singleton Manager Design Pattern is one thing I really like. I've been using it
since the days I first designed it in a commercial real-world program and it
works fine. I hope you enjoy it too!


<h3>Acknowledgements</h3>
==Acknowledgements==
I'd like to thank Anapum Kapoor and Ittay Freiman for initiating my thinking about the ASingletonST design again. Thanks to Ittay also for his basic idea about the singleton manager. Thanks again to the EDM/2 guys, I hope you can manage to keep EDM/2 alive (support them by writing lots of articles!).


<p>
#Stefan Ruck: ''[[Let's Talk About... Singleton]]'' , EDM/2, Volume 5 Issue 12
I'd like to thank Anapum Kapoor and Ittay Freiman for initiating my thinking
#Bjarne Stroustrup: ''The C++ Programming Language'', Second Edition, 1995, p. 576f
about the ASingletonST design again. Thanks to Ittay also for his basic idea
#Bjarne Stroustrup: ''The C++ Programming Language'', Second Edition, 1995, p. 514
about the singleton manager. Thanks again to the EDM/2 guys, I hope you can
#Bjarne Stroustrup: ''The C++ Programming Language'', Second Edition, 1995, p. 580
manage to keep EDM/2 alive (support them by writing lots of articles!).
#Bjarne Stroustrup: ''The C++ Programming Language'', Second Edition, 1995, p. 648


<p>
[[Category:C++ Articles]]
[1] Stefan Ruck,
                Let's Talk About... Singleton, EDM/2, Volume 5 Issue 12<br>
[2] Bjarne Stroustrup
    The C++ Programming Language, Second Edition, 1995, p. 576f<br>
[3] Bjarne Stroustrup
    The C++ Programming Language, Second Edition, 1995, p. 514<br>
[4] Bjarne Stroustrup
    The C++ Programming Language, Second Edition, 1995, p. 580<br>
[5] Bjarne Stroustrup
    The C++ Programming Language, Second Edition, 1995, p. 648<br>

Latest revision as of 06:55, 27 December 2022

Written by Stefan Ruck

In December 1997 I introduced my version of the Singleton template class in EDM/2 [1]. Now, some time has gone by and Anapum Kapoor and Ittay Freiman inspired me to rethink the design. If you haven't done so yet, please read my original article first to be able to understand all the points I discuss here.

Another Approach - (Nearly) The Same Result

As promised in the first Singleton article, I will first show you another way to attain nearly the same result. Why I say 'nearly' will be explained shortly.

Björn Fahller, another EDM/2 author, was the first who showed me a different way to achieve the goals of a singleton. And since I feel he provided a really good explanation, I will just quote his mail. From now on, I will refer to this implementation as the 'static singleton'. Here is what Björn wrote:

The way out is totally different:

class X // our singleton class
{
// whatever.
// Make sure assignment and all constructors are private.
public:
  static X& instance(void);
};

X& X::instance(void)
{
  static X x;
  return x;
}

Figure 1: Static Singleton

Whenever you need your singleton in your code, call:

X::instance().someMethod();

Sure, different syntax, but the meaning is the same, and it's safe from the semantic drawbacks (it'll even be destroyed.) It has one potential real drawback, though. The object is constructed the first time used, which makes it very improper for real-time systems (you never know which call will create it, and thus cannot know how long a call will take).

That's what Björn wrote. Now you might ask what's the difference besides having less code (no reference counting is needed and no template class). There are two. First, the static singleton is located in the program's static storage, while mine is put on the heap since it is created by calling the new constructor. Secondly, once a static singleton is created, it can't be destroyed. My implementation destroys the singleton as soon as the reference counter reaches zero, in other words, once the singleton is no longer eeded. This is a very important fact to remember for later on.

But if you do not need or want to destroy and recreate a singleton at runtime, I think the static singleton is the way to go.

The (Temporary) Singleton Implementation Class

Writing sample code for this article, I first decided to create a little helper to avoid having to recode a few methods for each singleton class.

Looking at the sample code in [1], you might notice it's necessary to implement the static data members m_ulReferenceCounter, m_pInstance and the static methods instance() and releaseInstance() for each class that should be used as a singleton. Of course, copy and paste goes very fast, but there are ways in C++ to avoid this.

First, you might ask why not creating a base class which implements these four members. This is not desirable for two reasons. First, you might need multiple inheritance which is not allowed in all organizations (for whatever reasons). Secondly, the base class can only handle a pointer of its own type, not of the final singleton class, since we can't know each derived class will ever be created when defining it. So this is not the solution.

What can we do? Reading a little bit about Microsoft's ATL gave me the final idea. A client of a singleton based on my ASingletonST class can only call its public members. Also, a default constructor is necessary to clearly initialize the object without having to use any sort of initialization method. So why not have a class that uses the singleton class as its base class? implements the singleton specific members and is the one used by ASingletonST. This can easily be done by using a template class. Here is the declaration:

template <class T>
class ASingletonImpl : public T
{
  public:
    // number of users
    static unsigned long referenceCounter ()
      { return (ASingletonImpl <T> :: m_ulReferenceCounter); }

  protected:
    ASingletonImpl () { }

 private:
    // not implemented
    ASingletonImpl (const ASingletonImpl <T> & rSource);

    // not implemented
    ASingletonImpl <T> & operator = (const ASingletonImpl <T> & rSource);

    // return the instance
    static ASingletonImpl <T> * instance ();

    // release the instance
    static void releaseInstance ();

    // pointer to the single instance
    static ASingletonImpl <T> * m_pInstance;

    // counts the instance requests
    static unsigned long m_ulReferenceCounter;

    friend class ASingletonST <T>;
};

Figure 2: The Singleton Implementation Class

The implementation of the class looks like this:

// initialize the pointer
template <class T>;
ASingletonImpl <T> * ASingletonImpl <T> :: m_pInstance = 0L;

// initialize the counter
template <class T>

unsigned long ASingletonImpl <T> :: m_ulReferenceCounter = 0L;

//****************************************************************
// ASingletonImpl :: instance - returns a pointer to the instance*
//****************************************************************

template <class T>
ASingletonImpl <T> * ASingletonImpl <T> :: instance ()

{
  // do we have an instance already?
  if (!m_pInstance)
      // no, allocate it
      m_pInstance = new ASingletonImpl <T>;

  // increase the counter
  ++m_ulReferenceCounter;

  // return the pointer to the instance
  return (m_pInstance);
}

//***********************************************************
// ASingletonImpl :: releaseInstance - releases the instance*
//***********************************************************

template <class T>

void ASingletonImpl <T> :: releaseInstance ()

{
  if (!m_ulReferenceCounter)  // no instance allocated?
      return;                 // yes, return
  // decrease the number of active users
  --m_ulReferenceCounter;
  // is the instance still in use?
  if (m_ulReferenceCounter)
      return;                 // yes, return
  delete m_pInstance;        // delete the instance
  m_pInstance = 0L;          // reset the pointer
}

Figure 3: Implementation of the Singleton Implementation Class

Comparing this to the implementation of the sample code in [1], you will notice two differences. The somewhat cryptic declaration of the static data members and the allocation of an object of type ASingletonImpl <T> instead of the singleton class itself in the instance() method. The rest has been left unchanged.

The Drawbacks

I used IBM's VisualAge 4.0 compiler to implement the sample code with ASingletonImpl and a modified version of ASingletonST. This compiler has one big advantage against any other compiler I know: you don't need to worry about #include statements in any file. Just put all the includes you need into the project's configuration file and the compiler will do the job.

Trying to use these classes at work with Microsoft's VC++ 6.0 I ran into unresolvable problems because of cross-references between ASingletonST and ASingletonImpl. The result was I couldn't use the classes.

The Next ASingletonST Generation

Thinking about it a bit, I asked myself why not combine the advantages of ASingletonImpl with ASingletonST. No sooner thought than done. ASingletonST got a new interface and implementation.

template <class T>

class ASingletonST

{
  public:
    ASingletonST ()          // constructor
      { instance (); }
    virtual ~ASingletonST () // destructor
      { releaseInstance (); }

    T * operator -> ();

    T &  operator * ();

  private:
    // not implemented
    ASingletonST (const ASingletonST <T> & rSource);
    // not implemented
    ASingletonST <T> & operator = (const ASingletonST <T> & rSource);

    // create the instance and/or increment refcount
    static void instance ();

    // release the instance
    static void releaseInstance ();

    // pointer to the one and only instance
    static T * m_pInstance;

    // reference counter
    static unsigned long m_ulReferenceCounter;
};

Figure 4: ASingletonST's New Interface

The new implementation of ASingletonST looks like this.

// define and initialize the pointer
template <class T>
T * ASingletonST <T> :: m_pInstance = 0L;

// define and initialize the counter
template <class T>
unsigned long ASingletonST <T> :: m_ulReferenceCounter = 0L;

//*****************************************************************
// ASingletonST :: operator -> - returns a pointer to the instance*
//*****************************************************************

template <class T>
T * ASingletonST <T> :: operator -> ()
{
  if (!m_pInstance)
      instance ();

  return (m_pInstance);
}

//******************************************************************
// ASingletonST :: operator * - returns a reference to the instance*
//******************************************************************

template <class T>

T & ASingletonST <T> :: operator * ()
{
  if (!m_pInstance)
      instance ();

  return (*m_pInstance);
}
//********************************************************
// ASingletonST :: instance - create the instance and/or *
//                            increment refcount         *
//********************************************************

template <class T>
void ASingletonST <T> :: instance ()
{
  // do we have an instance already?
  if (!m_pInstance)
      // no, allocate it
      m_pInstance = new T;

  // increase the counter
  ++m_ulReferenceCounter;
}

//***********************************************************
// ASingletonST :: releaseInstance - releases the instance  *
//***********************************************************

template <class T>
void ASingletonST <T> :: releaseInstance ()
{
  if (!m_ulReferenceCounter)  // no instance allocated?
      return;                 // yes, return

  // decrease the number of active users
  --m_ulReferenceCounter;

  // is the instance still in use?
  if (m_ulReferenceCounter)
      return;                // yes, return

  delete m_pInstance;        // delete the instance

  m_pInstance = 0L;          // reset the pointer
}

Figure 5: Implementation of the new ASingletonST Class

To avoid any complications, I've made the copy constructor and assignment operator private and didn't implemented them. Since I know now that an explicit call of the destructor is possible [2], I've expanded the members for security reasons. Using this version, it is safe (but not desirable) e.g. to call ASingletonST's destructor and afterwards the -> operator.

Implementing a 'real' singleton class using ASingletonST requires only two things: be sure to declare operator= and all constructors as private and make ASingletonST<class> a friend of it.

But ASingletonST also gives you the ability to use any class as a singleton. One thing about classes not designed as singletons is that you can't prevent them from not being used by others as a singleton.

The Singleton Manager Design Pattern

Ittay Freiman was the first who introduced the idea of a 'singleton manager' since he had the problem of using singletons depending on each other and so needed something that controls the sequence of their construction and destruction.

Using a static singleton makes it impossible to exercise control over the sequence since the sequence in which local static objects are destroyed is not defined (see C++ Reference Manual [3]).

So my solution of using pointers and reference counting is needed.

The singleton manager's task is to take control over the sequence of creation and destruction of singletons that depend on each other.

Therefore, it needs to be created before any client might need any singleton and should be destroyed only when no one needs any more singletons.

One thing really helpful here is the definition of when the constructors and destructors of data members are called. The Standard says "First, the base classes are initialized in declaration order ..., then the members are initialized in declaration order (independent of the order of mem-initializers)... The declaration order is used to ensure that ... members are destroyed in the reverse order of initialization." [4].

With this in mind, it's quite easy to create a singleton manager that ensures the right sequence of singleton creation and destruction. Just declare a data member for each singleton needed in the right sequence: independent singletons first, dependent ones later.

If, for whatever reason, you need a different order of destruction, you might call the destructor of the data members inside the manager's destructor in the sequence you need. This is why I check for a valid instance in ASingletonST::operator-> and ASingletonST::operator*. You can (but I think should not) call the destructor of a class whenver you like.

A First Attempt

To fulfil the tasks described above, you might create a singleton manager which looks like this:

class ASingletonManager
{
public:
  virtual ~ASingletonManager();
//whatever
private:
  ASingletonST<class1> m_Class1;
  ASingletonST<class2> m_Class2;
  ASingletonST<class3> m_Class3;
}

Figure 6: A Singleton Manager

And to alter the singleton destruction sequence from the default, you could code the destructor like this:

ASingletonManager::~ASingletonManager()
{
  m_Class1.ASingletonST<class1>::~ASingletonST();
  m_Class3.ASingletonST<class3>::~ASingletonST();
  m_Class2.ASingletonST<class2>::~ASingletonST();
}

Figure 7: Example of Controlling the Sequence of Destruction

In this sample, m_Class1 will be initialized first, then m_Class2 and lastly m_Class3. Assuming there is no other client currently using one of the singletons, in ASingletonManager::~ASingletonManager() the class1 singleton will be destroyed first, then class3 and finally class2. The order without an explicit call to ASingletonST<>::~ASingletonST() would be class3 first, class2 second and class1 third.

But this example conflicts with the ANSI/ISO standard which says "A destructor may not be invoked more than once for an object"[5]. Here, it will be called twice: first explicit by the manager's destructor, and later implicitly when ASingletonManager's data members are destroyed.

To be completely free of any declaration order, you need to implement the ASingletonST members of the manager as pointers, which will be allocated by the constructor, independent of the order in which the pointer members are declared.

class ASingletonManager
{
public:
  ASingletonManager();
  virtual ~ASingletonManager();
//whatever
private:
  ASingletonST<class1> * m_pClass1;
  ASingletonST<class2> * m_pClass2;
  ASingletonST<class3> * m_pClass3;
}

ASingletonManager :: ASingletonManager()
                     : m_pClass1 (0L),
                       m_pClass2 (0L),
                       m_pCLass3 (0L)
{
  m_pClass2 = new ASingletonST<class2>;
  m_pClass3 = new ASingletonST<class3>;
  m_pClass1 = new ASingletonST<class1>;
}

ASingletonManager :: ~ASingletonManager()
{
  delete m_pClass3;
  delete m_pClass1;
  delete m_pClass2;
}

Figure 8: Using Pointers to ASingletonST

Any time the program needs an instance of the singleton, an object of ASingletonST<class> can be created and used. The instance returned by this object is the one created by the singleton manager. But remember to make sure a manager is created before any user creates an ASingletonST<> object that refers to a singleton handled by the singleton manager. And the manager must stay alive until no more managed singletons are needed.

Another (Better) Way

Implementing a singleton manager as described above, you have to take care that the singleton manager is the first to reference the singleton and the last to free the reference.

To eliminate this disadvantage, some changes are needed. We have to make sure that no client can create a singleton without using the singleton manager.

So first declare the constructors of any class which should have only one instance as private and make the singleton manager a friend class. Second, implement the manager itself as a singleton. Third, implement a public interface to access the 'one-instance' members.

The 'one-instance' classes don't need to be designed as singletons any more since no one but the singleton manager can create an object of that class. Only the manager must be a singleton. Now any client that needs access to the 'one-instance' objects first needs to create an object of ASingletonST<SingletonManager> which guarantees the right construction and destruction order of the 'one-instance' objects. The 'one-instance' objects can only be accessed through the singleton manager's interface.

The sample code below shows how to do it, using the new ASingletonST class.

class A
{
public:
        ~A() { cout << "A::~A" << endl; }

        void text() { cout << "A::text" << endl; }

private:
        A () { cout << "A::A" << endl; }
        A (const A & rSrc); // not implemented

        // not implemented
        const A & operator= (const A & rSrc);

        friend class ASingletonManager;
};

class BDependsOnA
{
public:
        ~BDependsOnA() { cout << "BDependsOnA::~BDependsOnA" << endl; }

        void text() { cout << "BDependsOnA::text" << endl; }

private:
        BDependsOnA () { cout << "BDependsOnA::BDependsOnA" << endl; }
        BDependsOnA (const BDependsOnA & rSrc); // not implemented

        // not implemented
        const BDependsOnA & operator= (const BDependsOnA & rSrc);

        friend class ASingletonManager;
};

class ASingletonManager
{
public:
        virtual ~ASingletonManager()
    { cout << "ASingletonManager::~ASingletonManager" << endl; }

        A & a() { return (m_A); }
        BDependsOnA & bDependsOnA() { return (m_BDependsOnA); }

private:
        ASingletonManager()
    { cout << "ASingletonManager::ASingletonManager" << endl; }

        // not implemented
        ASingletonManager(const ASingletonManager & rSrc);

        // not implemented
        const ASingletonManager &
        operator=(const ASingletonManager & rSrc);

   A m_A;
   BDependsOnA m_BDependsOnA;

   friend class ASingletonST<ASingletonManager>;
};

void f2()
{
        cout << "f2" << endl;
        ASingletonST<ASingletonManager> pSingletonManager;
        pSingletonManager->bDependsOnA().text();
        pSingletonManager->a().text();
}

void f1()
{
        cout << "f1" << endl;
        ASingletonST<ASingletonManager> pSingletonManager;
        pSingletonManager->a().text();
        f2();
        pSingletonManager->bDependsOnA().text();
}

void main()
{
        f1();
}

Figure 9: Example of Using the Singleton Manager

The output of the sample code is this:

f1
A::A
BDependsOnA::BDependsOnA
ASingletonManager::ASingletonManager
A::text
f2
BDependsOnA::text
A::text
BDependsOnA::text
ASingletonManager::~ASingletonManager
BDependsOnA::~BDependsOnA
A::~A

Figure 10: Sample Code Output

You might wonder why A::A and BDependsOnA::BDependsOnA is printed out before ASingletonManager::ASingletonManager. The answer is that the constructors of A and BDependsOnA are called during member initialization which occurs before the ASingletonManager::ASingletonManager code is executed.

Conclusion

I think it's much easier now to create singletons using the new ASingletonST template class. It saves you from having to code singleton implementation details over and over again, lets you put the focus on the singleton classes and allows you to use classes never meant to be singletons as singletons.

The Singleton Manager Design Pattern is one thing I really like. I've been using it since the days I first designed it in a commercial real-world program and it works fine. I hope you enjoy it too!

Acknowledgements

I'd like to thank Anapum Kapoor and Ittay Freiman for initiating my thinking about the ASingletonST design again. Thanks to Ittay also for his basic idea about the singleton manager. Thanks again to the EDM/2 guys, I hope you can manage to keep EDM/2 alive (support them by writing lots of articles!).

  1. Stefan Ruck: Let's Talk About... Singleton , EDM/2, Volume 5 Issue 12
  2. Bjarne Stroustrup: The C++ Programming Language, Second Edition, 1995, p. 576f
  3. Bjarne Stroustrup: The C++ Programming Language, Second Edition, 1995, p. 514
  4. Bjarne Stroustrup: The C++ Programming Language, Second Edition, 1995, p. 580
  5. Bjarne Stroustrup: The C++ Programming Language, Second Edition, 1995, p. 648