// Purpose.
Singleton // New
design. "globalObj" is now a
// // private static data member
of its
// Discussion. On the left, a global // own class. Global access is pro-
// object is architected to require // vided by the public static member
// lazy initialization (not inited un- // function inst(). And the lazy
// til it is needed). This
requires // initialization code is
encapsu-
// all users of the
object to test and // lated in the
inst() function.
// potentially
allocate the pointer. //
GlobalClass's ctor and dtor have
// Singleton suggests making the class // been made protected so that cli-
// itself responsible for creating, // ents cannot create more inst's
// maintaining, and providing global // or destroy the Singleton inst.
// access to its own single instance.
class
GlobalClass {
#include
<iostream.h>
public:
int getValue()
{
class GlobalClass { return value_;
}
public: void
setValue( int v ) {
GlobalClass( int v=0 ) { value_ = v; }
value_ = v; } static GlobalClass* inst() {
int
getValue() {
if ( ! globalObj_ )
return value_; } globalObj_ = new GlobalClass;
void setValue( int v ) { return globalObj_; }
value_ = v; } protected:
private: GlobalClass( int v=0 ) {
int
value_;
value_ = v; }
};
~GlobalClass() { }
private:
// Initializing a global ptr to class int
value_;
// GlobalClass static
GlobalClass* globalObj_;
GlobalClass* globalObj =
0; };
void foo( void ) //
Allocating and initializing
{ //
GlobalClass's static data member
if ( ! globalObj )
// (the ptr, not a GlobalClass inst)
globalObj = new GlobalClass; GlobalClass*
globalObj->setValue( 1 ); GlobalClass::globalObj_ = 0;
cout << "foo: globalObj is
" <<
globalObj->getValue() << endl; void foo( void )
} {
GlobalClass::inst()->setValue( 1 );
void bar( void ) cout << "foo: globalObj is
" <<
{
GlobalClass::inst()->getValue()
if ( ! globalObj ) << endl;
globalObj = new GlobalClass; }
globalObj->setValue( 2 );
cout << "bar: globalObj is " << void bar( void )
globalObj->getValue() <<
endl; {
}
GlobalClass::inst()->setValue( 2 );
cout << "bar: globalObj is "
<<
void main( void )
GlobalClass::inst()->getValue()
{ << endl;
if ( ! globalObj ) }
globalObj = new GlobalClass;
cout << "main: globalObj is
" << void main( void
)
globalObj->getValue()
<< endl; {
foo(); cout << "main:
globalObj is " <<
bar(); GlobalClass::inst()->getValue()
} << endl;
foo();
// main: globalObj
is 0 bar();
// foo: globalObj is 1 }
// bar: globalObj is 2
//
main: globalObj is 0
// foo: globalObj is
1
// bar: globalObj is 2
// Purpose. Singleton
destroyer class
GlobalClass;
//
// Discussion. Vlissides describes
class SingDest {
// that
Singletons can be cleaned-up
public:
// by
"wrapping" the ptr in a stack-
SingDest( GlobalClass* s=0 ) {
// based static member of another sing_ = s; }
// class whose sole responsibility is ~SingDest();
//
to have its destructor delete the
void setSing( GlobalClass* s ) {
// Singleton's ptr. The
Singleton sing_ = s; }
// destroyer is automatically cre- private:
// ated before main() is run, and GlobalClass*
sing_;
// initially
contains a null ptr. };
// The first time the inst() method
// is called, the destroyer is class GlobalClass {
// meaningfully initialized. public:
friend class SingDest;
#include <iostream.h> int
getValue() { return value_; }
void setValue( int v )
{
class GlobalClass { value_ = v; }
public: static GlobalClass* inst() {
int
getValue() {
if ( ! globalObj_ ) {
return value_; } globalObj_ = new GlobalClass;
void setValue( int v ) { dest_.setSing(
globalObj_ ); }
value_ = v;
} return
globalObj_; }
static
GlobalClass* inst() {
private:
if ( !
globalObj_ )
GlobalClass( int v=0 ) {
globalObj_ = new GlobalClass;
cout << ":ctor:
";
return globalObj_;
} value_ = v; }
protected: ~GlobalClass() {
GlobalClass( int v=0 ) { cout <<
":dtor:" << endl; }
value_ = v; }
int value_;
~GlobalClass() { } static GlobalClass*
globalObj_;
private: static
SingDest dest_;
int value_; };
static GlobalClass* globalObj_;
}; GlobalClass*
GlobalClass::globalObj_ = 0;
// Allocating and initializing SingDest GlobalClass::dest_;
// GlobalClass's static data member SingDest::~SingDest() { delete sing_;
}
// (the ptr, not a GlobalClass
inst)
GlobalClass* void foo( void )
{
GlobalClass::globalObj_ =
0;
GlobalClass::inst()->setValue( 1 );
cout <<
"foo: globalObj is " <<
void foo( void ) {
GlobalClass::inst()->getValue()
GlobalClass::inst()->setValue( 1 ); << endl;
cout << "foo: globalObj is
" << }
GlobalClass::inst()->getValue() void bar( void ) {
<< endl;
GlobalClass::inst()->setValue( 2 );
} cout << "bar:
globalObj is " <<
void
bar( void ) {
GlobalClass::inst()->getValue()
GlobalClass::inst()->setValue( 2 ); << endl;
cout << "bar: globalObj is
" << }
GlobalClass::inst()->getValue() void main( void ) {
<< endl; cout <<
"main: globalObj is " <<
}
GlobalClass::inst()->getValue()
void main( void ) { << endl;
cout << "main: globalObj is
" << foo();
GlobalClass::inst()->getValue() bar();
<< endl; cout << "main: end"
<< endl;
foo(); }
bar();
} // main: globalObj is :ctor:
0
// foo: globalObj is 1
//
main: globalObj is 0 //
bar: globalObj is 2
// foo:
globalObj is 1 // main:
end
// bar: globalObj is 2 // :dtor:
// Purpose.
Singleton (Scott Meyers // New
design. "globalObj" is now
a
// approach) // static variable in the inst() ac-
// Discussion. On the left, a global //
cessor method. The single inst-
// object is architected to require // ance is enforced by declaring
the
// lazy initialization (not
inited un- // ctor non-public. [The dtor must
// til it is needed). This requires // be public because of the static
// all users of the object to test and // variable instance.] Global
// potentially allocate the pointer. // access is provided by the static
// Singleton suggests making the class // inst() method. The object is al-
//
itself responsible for creating, //
located on first demand by C++,
//
maintaining, and providing global //
and it is de-allocated automati-
// access to its own single instance. // cally by C++.
#include <iostream.h> #include <iostream.h>
class GlobalClass { class GlobalClass {
public: public:
GlobalClass( int v=0 ) { int getValue() {
value_ = v; } return value_; }
int
getValue() {
void setValue( int v ) {
return value_; }
value_ = v; }
void
setValue( int v ) {
static GlobalClass& inst() {
value_ = v; } static GlobalClass globalObj;
private: return globalObj; }
int
value_;
~GlobalClass() {
};
cout << ":dtor:" << endl; }
protected:
// Initializing
a global ptr to class GlobalClass(
int v=0 ) {
// GlobalClass cout <<
":ctor: ";
GlobalClass* globalObj =
0; value_ = v; }
private:
void foo( void
) int value_;
{ };
if ( ! globalObj )
globalObj = new GlobalClass; void foo( void )
globalObj->setValue( 1 ); {
cout << "foo: globalObj is " << GlobalClass::inst().setValue( 1
);
globalObj->getValue()
<< endl; cout <<
"foo: globalObj is " <<
}
GlobalClass::inst().getValue()
<< endl;
void bar( void ) }
{
if ( ! globalObj
) void bar( void
)
globalObj = new
GlobalClass; {
globalObj->setValue( 2 ); GlobalClass::inst().setValue( 2
);
cout << "bar:
globalObj is " <<
cout << "bar: globalObj is " <<
globalObj->getValue() <<
endl;
GlobalClass::inst().getValue()
} << endl;
}
void main( void )
{ void main( void )
if ( ! globalObj ) {
globalObj = new GlobalClass; cout << "main: globalObj
is " <<
cout
<< "main: globalObj is " << GlobalClass::inst().getValue()
globalObj->getValue() << endl; << endl;
foo(); foo();
bar(); bar();
} cout << "main:
end" << endl;
}
// main: globalObj is 0
// foo: globalObj is 1 // main: globalObj is :ctor:
0
// bar: globalObj is 2 // foo: globalObj is 1
//
bar: globalObj is 2
// main: end
//
:dtor:
// Purpose.
Singleton design pattern
// 1. Define a private static
attribute in the "single instance" class
// 2. Define a public
static accessor function in the class
// 3. Do "lazy
initialization" (creation on demand) in the accessor function
// 4.
Define all constructors to be protected or private
// 5. Clients may only
use the accessor function to manipulate the Singleton
// 6. Inheritance
can be supported, but static functions may not be overridden.
// The base class must be declared a friend
of the derived class (in order
//
to access the protected constructor).
#include
<iostream>
#include <string>
#include
<stdlib.h>
using namespace std;
class Number {
public:
static
Number* instance(); // 2.
Define a public static accessor func
static void setType( string t )
{ type = t; delete inst; inst = 0;}
virtual void setValue( int in )
{ value = in; }
virtual
int getValue() { return value; }
protected:
int value;
Number() { cout << ":ctor: "; } // 4. Define all ctors to be protected
private:
static string type;
static
Number* inst; // 1. Define a
private static attribute
};
string Number::type = "decimal";
Number* Number::inst =
0;
class Octal : public Number { // 6. Inheritance can be supported
public:
friend class Number;
void setValue( int in ) {
char buf[10];
sprintf( buf, "%o", in
);
sscanf( buf, "%d", &value );
}
protected:
Octal() { }
};
Number*
Number::instance() {
if ( !
inst)
// 3. Do "lazy
initialization" in the accessor function
if (type == "octal") inst = new Octal();
else inst = new Number();
return inst;
}
void main(
void ) {
// Number myInstance; --- error: cannot access
protected constructor
// 5.
Clients may only use the accessor function to manipulate the Singleton
Number::instance()->setValue( 42
);
cout << "value is
" << Number::instance()->getValue() << endl;
Number::setType( "octal" );
Number::instance()->setValue( 64
);
cout << "value is
" << Number::instance()->getValue() << endl;
}
//
:ctor: value is 42
// :ctor: value is 100