A Leak-Free Singleton Class

The singleton pattern given in the book "Design
Patterns" [1]
has the problem that the memory allocated
on the heap is not freed anywhere which results in a memory leak.
The C++ class given below is one way of implementing the
singleton pattern without a leak. The class given, however, does
not address such issues as multi-threading or inheritance.

Acknowledgements

Acknowledgement is due primarily to all the programmers taking
part in http://www.codeguru.com
providing their skills and expertise to help other programmers.
A special thanks is due to Mike Junkin who took the time and
trouble to answer my queries and who is indirectly responsible
for my compulsion in writing this article…

Table of Contents

  1. Software Environment
  2. The CSingleton Class
  3. Source Code
  4. By Way of Explanation
  5. Executable Checks
  6. Microsoft C++ Standard Library
  7. Other Issues
  8. Conclusions
  9. References

Software Environment

  • Microsoft Visual C++ 5.0 with Service Pack 3
  • NuMega BoundsChecker version 5.0
  • OS: NT4.0 with Service Pack 3
  • PC: HP Vectra, 32MB RAM, P200MMX

 

The CSingleton Class

To use the code, the header file "Singleton.h" must
be #include’d and space must be reserved for a static member
pointer. Assuming we have a class called MyClass which we wish to
make into a singleton we would do the following:

MyClass.cpp


#include "Singleton.h"
#include "MyClass.h"

typedef CSingleton<MyClass> tMyClass;
tMyClass::InstPtr tMyClass::sm_ptr;

The typedef will be used later on as well. The above code
instantiates a CSingleton which, via the template mechanism,
allows access to the user-defined class, MyClass. This is an
example of a programming idiom known variously as "envelope
/ letter", "handle / body " and "Proxy
Classes" [2]. To access the
singleton-wrapped user class "MyClass" we then use the
static Instance() method of the CSingleton class:

MyClass* pMyClass = tMyClass::Instance();

We can then use the pointer to the user-class in the usual
way:


MyClass* pMyClass = tMyClass::Instance();
if ( pMyClass != 0 )
{
pMyClass->DoSomething();
}

 

Source Code

Singleton.h


#ifndef _SINGLETON_H_
#define _SINGLETON_H_
//
// PROJECT: Feasibility
// FILENAME: Singleton.h
// ORIGINAL AUTHOR: Paul Whitehead
// ORIGINAL CREATION DATE: 11th Jan 1999
// DESIGN DOCUMENT NO.:
//
// DESCRIPTION:
//
// $Date$
//
// $Log$
//

template<class T>
class CSingleton
{
private:
class InstPtr
{
public:
InstPtr() : m_ptr(0) {}
~InstPtr() { delete m_ptr; }
T* Get() { return m_ptr; }
void Set(T* p)
{
if(p!= 0)
{
delete m_ptr;
m_ptr = p;
}
}
private:
T* m_ptr;
};

static InstPtr sm_ptr;
CSingleton();
CSingleton(const CSingleton&);
CSingleton& operator=(const CSingleton&);

public:
static T* Instance()
{
if(sm_ptr.Get() == 0)
{
sm_ptr.Set(new T());
}
return sm_ptr.Get();
}
};

#endif // #ifndef _SINGLETON_H_

OneOf.cpp – Example Client


//
// PROJECT: Feasibility
// FILENAME: OneOf.cpp
// ORIGINAL AUTHOR: Paul Whitehead
// ORIGINAL CREATION DATE: 11th Jan 1999
// DESIGN DOCUMENT NO.:
//
// DESCRIPTION:
//
// $Date$
//
// $Log$
//

#include <iostream>
#include "Singleton.h" // CSingleton

using namespace std;

class OneOf
{
public:
void SayHello() { cout << "Hello World!" << endl; }
};

typedef CSingleton<OneOf> tOneOf;
tOneOf::InstPtr tOneOf::sm_ptr;

int main()
{
OneOf* pOne = tOneOf::Instance();
if(pOne != 0)
{
pOne->SayHello();
}
return 0;
}

One thing that may appear odd to C programmers is checking
pointers against the value 0 and not NULL. This is perfectly
correct [3].

 

By Way of Explanation

Perhaps some points of explanation would be a good idea. The
basic idea behind the singleton is given in [4] and will not be re-iterated here.

The problem with the singleton design pattern as presented in [4] is that the memory allocated on the
heap is nowhere deleted. To provide such a deletion mechanism a
standard technique is employed of using some form of smart
pointer. A smart pointer is one which replaces a standard pointer
and adds functionality. The C++ standard library, for example,
defines a class known as auto_ptr<> which automatically
frees any resource it is controlling when its destructor is
called. This is useful for when the pointer assumes ownership of
a dynamically allocated resource. In this case a simple local
variable of auto_ptr which accepts the allocated pointer will
free the allocated resource when it goes out of scope. Consider
the following:


MyClass* ReadDiskItems(CFile& DiskFile);

void ProcessDiskItems()
{
CFile MyFile("c:\\abc.123");
auto_ptr<MyClass> ptr = ReadDiskItems(MyFile);
DoSomethingWithData(ptr);
}

Here, ReadDiskItems() will read a file from disk, allocate
memory for the data and return. The auto_ptr class will take
ownership of the memory. We then process the data and the
function ProcessDiskItems() returns. When a function returns, any
local variables (unless they’re static) are destroyed. As part of
the return mechanism, then, the destructor for the class auto_ptr
is called. This will free the resource it controls and we don’t
get any memory leaks. You could get a normal pointer and call
delete on it yourself, but this kind of situation occurs so
frequently that the C++ committee decided to provide an auto_ptr
class as part of the C++ standard library (there is another
reason to do with exception handling but that is beyond the scope
of this article).

So how does that help us? The problem with the singleton
pattern is that there is a pointer which does not get deleted. We
could use some sort of smart pointer to manage that resource and
which, when it goes out of scope, would free-up the resource for
us. This is what the nested class InstPtr is doing in the above
code. It "manages" the pointer assigned to it. A
pointer is assigned to the InstPtr class via its Set() and
retrieved via its Get() method. The "raw" pointer is
kept in the private member m_ptr.

Meanwhile, back in the world of the CSingleton class, we have
a static private member which is an instantiation of the InstPtr
class. This pointer is accessed via the static public method
Instance(). Why you require static versions of these is covered
in the singleton pattern explanation [4].
The Instance() method uses lazy initialisation so that the memory
is only allocated for the class the first time it is required.
Once the user-defined class has been dynamically allocated the
pointer is returned. Subsequent calls to Instance() simply return
the same pointer. When it’s time to say goodbye to the singleton
class and it is being destroyed all its data members get
destroyed. One of the data members happens to be an object of the
nested class InstPtr. Thus the InstPtr destructor is called. This
destructor frees up the memory resource it is managing with the
result that the singleton pattern implemented by the CSingleton
class does not leak.

 

Executable Checks

A debug version of the executable was run through MS VisualC++
5.0 and integrated BoundsChecker. At the end of a program run
BoundsChecker tells us we have a leak of some 208 bytes allocated
by _malloc_dbg and not freed in the onexit() routine. Running the
same executable through BoundsChecker stand-alone this leak is
not reported. One other problem is found in mainCRTStartup() when
the executable is first loaded and is the following:

Invalid argument: LCMapStringW, argument 3, PTR;

This is internal to the Microsoft-provided libraries so
there’s not a lot we can do about it. What is perhaps more
interesting is that there are no leaks from the CSingleton class.

For completeness, the BoundsChecker output when using VC5 is
given below:

208 bytes _malloc_dbg leak

This leak is not attributable to the CSingleton
class. By removing the code to delete the pointer in the InstPtr
destructor and running the executable through BoundsChecker
stand-alone, we get the following:

1 byte leak with no delete in InstPtr destructor

Thus we can see that the action of the InstPtr class does
indeed delete the the allocated pointer and absence of the delete
code in the InstPtr destructor leads to the leak shown above.

Microsoft C++ Standard Library for
iostream

Appears to leak. Given a Win32 console application consisting
entirely of the following code:

basic.cpp


#include <iostream>
using namespace std;
int main()
{
cout << "Hello World!" << endl;
return 0;
}

We get the following output when running through VC5 with
BoundsChecker:

208 byte leak

When running with an integrated BoundsChecker we can see that
the leak is probably due to the Microsoft implementation of the
C++ standard library.
This leak is identical to the leak shown when using the
CSingleton class and running with an integrated BoundsChecker.

By building and running a minimal Win32 console application as
below:

minimal.cpp


int main()
{
return 0;
}

no leaks are reported from the integrated version of
BoundsChecker.

One further possibility may be present: not that the C++
iostream standard library leaks but that the way strings are
mapped to NT / Unicode. This may be a possibility given that we
have an invalid pointer to LCMapStringW. The basic.cpp source
file was modified to use Microsoft’s own iostream and not their
standard library implementation. This is show below:


#include <iostream.h>

int main()
{
cout << "Hello World!" << endl;
return 0;
}

Integrated BoundsChecker gave us this output:

208 byte leak

We can see that we do not get a leak. It thus seems safe to
conclude that:

  1. The Microsoft implementation of the C++ iostream standard
    library causes a leak
  2. The CSingleton class does not leak.

Other Issues

Smart Pointers

There are lots and lots and lots of versions of these. We
built our own very simple version as a nested InstPtr class which
does just what we require and no more. The C++ standard library
has an auto_ptr<> class which is a smart pointer. If you
get into using COM, smart pointers pop up all over the place:
CComPtr and CComQIPtr are just two of the more basic ones. The
reason why these are so important is that they manage such topics
as reference counting.

One possible mode of extension for the CSingleton class would
be to have some form of reference counting. Each time a pointer
was requested the reference count would be increased. Each time a
pointer was no longer required its reference count would be
decreased. When the reference count reached zero we could destroy
the object. How do we know when the pointer is no longer
required? One way would be for the client to call something like
a Release() function on the pointer (just like COM). This places
the burden on the client programmer and it is a possible source
of program error. We could, of course, have some sort of pointer
which would automatically call the Release() function when it
goes out of scope. Uh-oh! I can feel a smart pointer coming on…

Multi-threading

Multi-threading issues require the use of such devices as
Critical Sections, Mutexes and Semaphores to protect the class.
These are beyond the scope of this article. One issue that may be
worth mentioning is the use of InterlockedIncrement() and
InterlockedDecrement(). These are Win32 atomic operations which
are the multi-threaded version of ++ and –. These should be used
for incrementing and decrementing reference counts in
multi-threaded land.

By extending the class even further we’re moving more and more
into a full-blown multi-threaded class implementation. At this
stage, depending upon which direction you’re extending the class,
you may find yourself re-inventing the wheel so here’s a caveat:
check first that there’s nothing around which fits (or almost
fits) your requirements. If so, you’re better of using that or
subclassing it and adding your extra bits than re-writing a whole
load of stuff. The CSingleton class above has been useful in its
present form as a small, lightweight implementation of the
singleton design pattern. By all means re-use it but if you find
yourself adding lots of extras try scanning around for some other
pre-developed classes first.


Conclusions

A singleton pattern wrapper class has been presented which
overcomes the problem of memory leakage present in the example
given in "Design Patterns" [1].
The use of the CSingleton class has saved development time
already by being re-used 7 times so far and has allowed a more
robust implementation of some classes which only ever require to
be instantiated once. Issues such as multi-threading and
inheritance have not been addressed as these are primarily issues
of the context into which the singleton class may be
placed. Additionally, it was felt that embellishing the basic
CSingleton class with e.g. multi-threading would obscure the
basic mechanism of the class. Any further functional extensions
are left as an exercise for the programmer 🙂

Using the Microsoft C++ standard library implementation for
iostream produced a leak which may have looked like the
CSingleton class was leaking but this was, in fact, traced back
to the Microsoft library.

If you find any bugs please feel free to fix them :-). I would
appreciate an email telling me about any bug fixes, though. I’m
on ccMail and, for those in software dev, you can email
"Paul Whitehead" on Exchange / Outlook.


References

[1] "Design Patterns" by Gamma,
Holm, Johnson & Vlissides, Publishers: Addison-Wesley, ISBN
0-201-63361-2

[2] Envelope / Letter Idiom:

  1. Section 5.5, page 133 in "Advanced C++ Programming
    Styles and Idioms" by James Coplien, Publishers:
    Addison-Wesley, ISBN 0-201-54855-0
  2. Item 30: Proxy Classes, page 213 in "More Effective
    C++" by Scott Meyers, Publishers: Addison-Welsey,
    ISBN 0-201-63371-X

[3] Bjarne Stroustrup gives the
following reason:

"In C, it has been popular to define a macro NULL
to represent the zero pointer. Because of C++’s tighter type
checking, the use of plain 0, rather than any suggested NULL
macro, leads to fewer problems."
(Section 5.1.1, page 88 in "The C++
Programming Language 3rd Edition" by Bjarne Stroustrup,
Publishers: Addison-Wesley, ISBN 0-201-88954-4)

[4] The explanation of a singleton
pattern can be found starting on page 127 of the book given in [1]

Date Created: February 13, 1999

Date Updated: February 19, 1999 (minor reformatting)

More by Author

Previous article
Next article

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read