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)



Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds