// 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 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 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 #include 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 #include #include 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