Yolinux.com Tutorial

C++ Singleton design pattern

Example of a C++ Singleton class design pattern.

Related YoLinux Tutorials:

°Linux and C++

°C++ Unions & Structures

°C++ Enumerations

°C++ Templates

°C++ STL

°C++ STL Map

°C++ String Class

°C++ Coding Style

°C++ XML Beans

°C/C++ Dynamic Memory

°C++ Memory Corruption

°C/C++ Signal Handling

°C++ CGI

°Fork and exec

°Emacs and C/C++

°Advanced VI

°Google C++ Unit Test

°Jenkins CI

°Jenkins Plugins for C++

°YoLinux Tutorials Index




Free Information Technology Magazines and Document Downloads
TradePub link image


Free Information Technology Software and Development Magazine Subscriptions and Document Downloads


Why use a singleton class?

This design pattern and methodology ensures that only one instance of the C++ class is instantiated. It assures that only one object is created and no more. It is often used for a logging class so only one object has access to log files, or when there is a single resource, where there should only be a single object in charge of accessing the single resource. The singleton pattern discussed here gives the class itself, the responsibility of enforcement of the guarantee that only one instance of the class will be allowed to be generated.


Example of a C++ Singleton class:

File: logger.hpp
#include <string>

class Logger{
public:
   static Logger* Instance();
   bool openLogFile(std::string logFile);
   void writeToLogFile();
   bool closeLogFile();

private:
   Logger(){};  // Private so that it can  not be called
   Logger(Logger const&){};             // copy constructor is private
   Logger& operator=(Logger const&){};  // assignment operator is private
   static Logger* m_pInstance;
};
Note:
  • That the instance function returns a pointer to a static variable and thus is declared static.
  • Only the class function Instance can call the constructor. Public access to the constructor is denied.
  • The constructor, copy constructor and assignment operator are all private to ensure that the programmer using the singleton class can only create a single instance of the class using only the Instance() function.
  • The life of the singleton instantiation is for the duration of the application.

File: logger.cpp
#include <stddef.h>  // defines NULL
#include "logger.h"

// Global static pointer used to ensure a single instance of the class.
Logger* Logger::m_pInstance = NULL;  

/** This function is called to create an instance of the class. 
    Calling the constructor publicly is not allowed. The constructor 
    is private and is only called by this Instance function.
*/
  
Logger* Logger::Instance()
{
   if (!m_pInstance)   // Only allow one instance of class to be generated.
      m_pInstance = new Logger;

   return m_pInstance;
}

bool Logger::openLogFile(std::string _logFile)
{
   ...
   ...
   ...
}

...
...

Usage:

   ...
   ...

   Logger::Instance()->openLogFile("logFile.txt");

   ...
   ...


C++ Singleton class using inheritance:

In this example the base class enforces a singleton pattern.

File: base.hpp
// Singleton base class hpp file

class sBase
{
public:
   static sBase* instance();
   static bool exists();
   inline int getDataX(){ return mDataX; };
   inline int setDataX(int _in){ mDataX = _in; };
   virtual int getDataY() = 0;
   virtual int setDataY(int _in) = 0;
protected:
   sBase(int);
   virtual ~sBase(){};
   static sBase* mpoSssInstance;
private:
   int mDataX;
};

File: base.cpp
#include <stddef.h>  // defines NULL
#include <iostream>
#include "base.hpp"

// Singleton base class cpp file

sBase* sBase::mpoSssInstance = 0;  // Global initialization to facilitate singleton design pattern

sBase::sBase(int _initialValueX)
: mDataX(_initialValueX)
{
}

bool sBase::exists()
{
   return (mpoSssInstance != NULL); // Return true/false
}

sBase* sBase::instance()
{
   if(mpoSssInstance == 0) std::cout << "Class has not been created" << std::endl;

   return mpoSssInstance;
}

File: derived.hpp
// Singleton derived class hpp file

#include "base.hpp"

class sDerived : public sBase
{
public:
   static void create(int,int);
   virtual inline int getDataY(){ return mDataY; };
   virtual inline int setDataY(int _in){ mDataY = _in; };
protected:
   sDerived(int,int);      // Can't be called by non-member functions
   virtual ~sDerived() {}; // Can't be called by non-member functions
private:
   int mDataY;
};

File: derived.cpp
// Singleton derived class cpp file

#include <iostream>
#include "derived.hpp"

sDerived::sDerived(int _initialValueX, int _initialValueY)
: sBase(_initialValueX)
{
   mDataY =_initialValueY;
}

void sDerived::create(int _initialValueX, int _initialValueY)
{
   if(mpoSssInstance)
      std::cout << "Singleton has already been created" << std::endl;
   else
      mpoSssInstance = new sDerived(_initialValueX, _initialValueY);
}

File: main.cpp
#include <derived.hpp>
#include <iostream>
using namespace std;

// Program which uses singleton class

main()
{
   // Only one instance of the singleton class can be created
   sDerived::create(3,3);

   sDerived::instance()->setDataX(5);
   cout << sDerived::instance()->getDataX() << endl;

   sDerived::instance()->setDataY(7);
   cout << sDerived::instance()->getDataY() << endl;
}
Compile: g++ main.cpp derived.cpp base.cpp

Results: a.out
5
7

Note that the function calls are static calls to their global names using the scope resolution operator. The functions create() and instance() are defined as static functions in the class definitions. Note that static member functions do not have a this pointer as they exist independent of any objects of a class.


The Template Singleton class:

One can inherit a singleton class from a base class or use a template for each type of instantiation. The Base class and Derived class relationship offers flexibility as there are no design limits in the derived class.

The Template singleton is also flexible and is used in a manner where any class can be turned into a singleton by using this template.

File: singleton.hpp
#ifndef __SINGLETON_HPP_
#define __SINGLETON_HPP_
#include <stddef.h>  // defines NULL

template <class T>
class Singleton
{
public:
  static T* Instance() {
      if(!m_pInstance) m_pInstance = new T;
      assert(m_pInstance != NULL);
      return m_pInstance;
  }
protected:
  Singleton();
  ~Singleton();
private:
  Singleton(Singleton const&);
  Singleton& operator=(Singleton const&);
  static T* m_pInstance;
};

template <class T> T* Singleton<T>::m_pInstance=NULL;

#endif
Usage:
#include "singleton.hpp"

class Logger
{
public:
   Logger() {};
   ~Logger() {};
   bool openLogFile(string);
   void writeToLogFile(string);
   bool closeLogFile(string);
private:
   ...
   ...
};

bool Logger::openLogFile(std::string)
{
   ...
   ...
}

...
...

typedef Singleton<Logger> LoggerSingleton;   // Global declaration

main()
{
    ...

    LoggerSingleton::Instance()->openLogFile("logFile.txt");

    ...
}


The static stack variable Singleton class:

class Logger {
public:
  static Logger& Instance() {
    static Logger theLogger;   // Instantiated when this function is called
    return theLogger;
  }
  bool openLogFile(string logFile);
  void writeToLogFile(string sLine);
  bool closeLogFile(string logFile);

private:
  Logger();                                  // constructor is private
  Logger(Logger const&);                 // copy constructor is private
  Logger& operator=(Logger const&);  // assignment operator is private
  ~Logger();                                 // destructor is private
};
Note:
  • This version of a singleton class initializes when the Instance() function is called.
  • The Instance() function returns an instance instead of a pointer. The pointer is not exposed and thus a delete can not be inappropriately applied.
  • [Potential Pitfall]: This form of the singleton can present a problem because of the life expectancy of the object. If one singleton is instantiated within another, one must be keenly aware of the destructor call sequence.
Usage:
   ...
   ...

   Logger::Instance().openLogFile("logFile.txt");

   ...
   ...

Also see An Exception Correct C++ Singleton Template Base Class with Controlled Destruction Order


Other variations and tips:

Optimization option:
static Abc* Abc::Instance() // Singleton
{
    return mInstance ? mInstance : (mInstance = new Abc);
}
This should slightly reduce the number of computed operations and thus is slightly more optimized.


The examples given above use a C++ global static variable. Other variations of a singleton can use:
  • an environment variable.
  • a file (A lock file is often used to insure a single instance of a process).
  • a static STL list or STL map of values or paired values can be used by a singleton class as a singleton registry for other classes to verify singleton compliance.


BooksBooks:

Book image "Design Patterns"
by Erich Gamma, Richard Helm, Ralph Johnson, John M. Vissides
ISBN # 0201633612, Addison-Wesley Professional Computing Series

Object oriented design patterns by example in C++.

Amazon.com
Modern C++ Design: Generic Programming and Design Patterns Applied
by Andrei Alexandrescu
ISBN #0201704315, Addison-Wesley Professional

Reviews use of the Phoenix Singleton and policy template classes (allows policy choice for behavior control) to control a singletons lifetime.

Amazon.com
Design Patterns Explained: A New Perspective on Object-Oriented Design
by Alan Shalloway, James Trott
ISBN #0321247140, Addison-Wesley Professional

Java examples.

Amazon.com

   

    Bookmark and Share


Advertisements




Copyright © 2008 - 2013 by Greg Ippolito