
Joe Gottman wrote:
1) I strongly dislike your virtual operator=(const SingletonBase &). Most of the Singletons I use don't have any virtual functions, and I would rather not add any if I don't have to. In your comments you say you only define it to make sure that SingletonBase cannot be instantiated. Keeping the destructor (or all the constructors) non-public has the same effect.
2) It would be easier on users if, instead of Singleton<T> inheriting from T, you reversed it so that T must inherit from Singleton<T> (the curiously recurring template pattern). This would make it possible to communicate in both directions between T and Singleton<T>. It would also make it much easier to turn an existing class into a Singleton.
First I should note that I made some changes since the first version I posted, the new version is available at http://www.ezequal.com/chaos/libs/singleton_revised.h. Specifically, the singleton no longer has a static dependency on itself, so client code can control lifetimes much more dynamically. In addition, I made GetInst return a smart pointer containing a dependency so that GetInst will never fail. It looks like I should post some sample client code so that it is clear exactly how my design is intended to be used. It is a bit unusual, but actually very clean and safe: #include <iostream> #include "Singleton.h" using namespace utils; using namespace std; class A : public SingletonBase { public: A ( ) { cout << "A created\n"; } ~ A ( ) { cout << "A destroyed\n"; } void DoSomethingUseful ( ) { cout << "A being useful\n"; } }; class B : public SingletonBase { private: // 1) //Singleton < A > :: Dependency require_a; public: B ( ) { cout << "B created\n"; } ~ B ( ) { cout << "B destroyed\n"; } void DoSomethingUseful ( ) { cout << "B being useful\n"; Singleton < A > :: SingletonPtr instance = Singleton < A > :: GetInst ( ); instance->DoSomethingUseful ( ); } }; // 2) //Singleton < B > :: Dependency require_b; int main ( ) { cout << "Entering main\n"; { // 3) //Singleton < B > :: SingletonPtr instance = Singleton < B > :: GetInst ( ); //instance->DoSomethingUseful ( ); } cout << "Exiting main\n"; return 0; } If both points 2 and 3 stay commented out, no singletons are created. If 2 is uncommented, B will exist for the lifetime of the program. If 1 is also uncommented, A will exist before and after B is created and destroyed. If 2 remains commented but 3 is uncommented, the singletons are created in the scope where the instance is referenced, and destroyed when the scope exits. Singletons would be able to be reincarnated any number of times. The important thing to notice is the safety that is enforced at compile time: A) It is illegal at compile time to have a Singleton < T > where T does not derive from SingletonBase. B) It is illegal at compile time to create an instance of SingletonBase. It is also illegal to create an instance of a derived type, because SingletonBase makes assignment pure virtual, therefore making child classes pure virtual as well. C) Even though Singleton < T > overrides the assignment operator to become non abstract, it still cannot be created by client code because of it's private constructor and destructor. D) The singleton instance cannot be copied; only SingletonPtrs to it can be copied, which essentially just increase the number of dependencies. I cannot think of any way I could have enforced all of this if singleton only acted as a base class.