
Hi Jason, I haven't looked at singleton in any detail, so I can't answer your real question, but I wanted to offer a small suggestion, for what it's worth: Rather than having a special function spelled "define_to_enable_creation," I wonder if it would be reasonable to declare singleton_base's destructor as pure virtual, forcing client code such as test_singleton to implement a destructor. If you wanted to enable the virtual behavior only for extra checking in debug mode, that'd be fine too: class singleton_base { protected: #ifdef DEBUG virtual ~singleton_base() = 0; #endif // ... }; class test_singleton : public singleton_base { protected: ~test_singleton() { } // ... }; In debug mode, test_singleton's destructor is virtual as defined by its base class, and is necessary to implement. In release mode, test_singleton's destructor is not virtual unless you specify it to be. And implementing a trivial destructor like this is never harmful anyway. Just a thought, but I might be totally missing something :) Cheers, dr On Thu, 24 Mar 2005 10:27:13 -0500, Jason Hise <chaos@ezequal.com> wrote:
Early on, I had the idea to disable creation of a user's singleton by making the base class have one pure virtual function. The user's derived singleton would become an abstract class, and thus not be able to be instantiated. Then the user would refer to the singleton via an even further derived class, like follows:
class singleton_base { private: virtual void define_to_enable_creation ( ) = 0; };
template < typename Type > class singleton : public Type { private: virtual void define_to_enable_creation ( ) { }
protected: // constructors and such were here
public: // interface was here };
//-------------------------------------------------
class test_singleton : public singleton_base { public: void do_something ( ); };
int main ( ) { test_singleton t; // this line would not compile singleton < test_singleton > t2; // neither would this singleton < test_singleton >::pointer ptr; // this would be the only access mechanism ptr->do_something ( );
return 0; }
This idea concerned some originally because remembering to use singleton < test_singleton > instead of just test_singleton everywhere in client code could get ugly, and define_to_enable_creation was the only virtual function in the class, introducing what might be unacceptable overhead. As a result, I removed it and changed the design to a more conventional CRTP implementation. I resigned myself to the fact that the user would just need to remember to make the default ctor and dtor protected.
In the current incarnation of the library, the client singleton's constructors are protected, and to gain access to them the creator policies define their own private class internally which derives from the singleton type and makes the ctors and dtor public. This is similar to the pattern above, except that client code doesn't have to worry or know about that most derived rung on the class hierarchy.
If I were to re-enable the virtual function check to make the client singleton abstract, the overhead of using virtual functions would again come back. However, having it in place would prevent unsafe instantiations regardless of the access level client code uses for singleton constructors. So would there be any objections to reinstating this mechanism just in debug mode? This way unsafe instantiations could be caught, and in release mode you wouldn't have to pay for the catching mechanism at all. Thoughts?
-Jason
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost