
Jason Hise wrote:
I would like to get general feedback on a feature that has been requested. Some background:
Right now, my singleton pointer classes serve a variety of purposes. In the first place, they are the access mechanism for a singleton. Any pointer constructed immediately points to the singleton instance (or possibly null if the instance hasn't been created yet). If the singleton uses instant_creation, the first pointer created creates the singleton instance. When a member is accessed through a singleton pointer, an intermediate pointer type performs locking, and if lazy_creation is set it may also create the singleton instance. Regardless of the lifetime mechanism used, when the singleton instance gets destroyed all pointers instantly reflect this by becoming null.
It has been suggested that I provide a mechanism to get a bald pointer to the instance, such as an unsafe_ptr member function of either the pointer class or the singleton itself. I feel that such a mechanism would be very dangerous, because the bald pointer could not perform lazy creation, it would not lock the operations, and it would not reflect when the singleton is destroyed.
Are there instances in which allowing bald pointers to exist is necessary and/or useful?
The only instance that I can think of where you may want to do this is in a multi-threaded environment. And even then only in a very specific set of circumstances. Specifically, you may want to do this when you don't want the overhead of a lock, but, for some other reason, you can absolutely guarantee that concurrent access to the object (or parts of the object you are accessing) is valid. If I'm honest though, I'm having some difficulty convincing myself that something like this would actually genuinely be useful. Perhaps if you could get a "bald pointer" through a protected member, that was therefore only accessible to derived classes (hence the singletons themselves). This could be useful to build into a static access function that provided a safe pointer, but perhaps without the overhead of a lock? Personally, I would be quite reluctant to provide such a feature... Dave Handley

"Dave Handley" wrote: [bald pointer out of singleton]
The only instance that I can think of where you may want to do this is in a multi-threaded environment. And even then only in a very specific set of circumstances. Specifically, you may want to do this when you don't want the overhead of a lock, but, for some other reason, you can absolutely guarantee that concurrent access to the object (or parts of the object you are accessing) is valid. If I'm honest though, I'm having some difficulty convincing myself that something like this would actually genuinely be useful. Perhaps if you could get a "bald pointer" through a protected member, that was therefore only accessible to derived classes (hence the singletons themselves). This could be useful to build into a static access function that provided a safe pointer, but perhaps without the overhead of a lock?
The use case is a legacy code that accepts only bald pointer. A singleton may have function unsafe_get(). The object would be instantiated if not already. Code using its result will promise not to destroy given object. /Pavel

Pavel Vozenilek wrote:
"Dave Handley" wrote:
[bald pointer out of singleton]
The only instance that I can think of where you may want to do this is in a multi-threaded environment. And even then only in a very specific set of circumstances. Specifically, you may want to do this when you don't want the overhead of a lock, but, for some other reason, you can absolutely guarantee that concurrent access to the object (or parts of the object you are accessing) is valid. If I'm honest though, I'm having some difficulty convincing myself that something like this would actually genuinely be useful. Perhaps if you could get a "bald pointer" through a protected member, that was therefore only accessible to derived classes (hence the singletons themselves). This could be useful to build into a static access function that provided a safe pointer, but perhaps without the overhead of a lock?
The use case is a legacy code that accepts only bald pointer.
A singleton may have function unsafe_get(). The object would be instantiated if not already.
Code using its result will promise not to destroy given object.
/Pavel
In such cases, I wonder if it might be best for the user's singleton to provide the function: class Example : public singleton < Example > { // protected ctor and dtor public: Example * unsafe_get ( ) { return this; } }; That way not all singleons would need to suffer the 'security hole' just because a few need it. -Jason

I recently discovered that my singleton could potentially be used in a way other than as a base class. For example, to create and use a singleton instance of a class which could have other ordinary instances as well, one could just do: class Example { public: void foo ( ) { } }; // elsewhere... singleton < Example >::pointer ptr; ptr->foo ( ); In addition, one could make a singleton who's instance refers to another class by deriving from a singleton of that type, as follows (using the Example above): class ExampleSingleton : public singleton < Example > { private: ExampleSingleton ( ); ~ ExampleSingleton ( ); }; which would essentially create a shorter name for singleton < Example >. I need opinions: should this type of usage be allowed, or should I find some way to make it fail to compile? If allowed, should it be encouraged and/or documented? -Jason

On Sun, 13 Feb 2005 19:20:07 -0500, Jason Hise <chaos@ezequal.com> wrote:
I recently discovered that my singleton could potentially be used in a way other than as a base class. For example, to create and use a singleton instance of a class which could have other ordinary instances as well, one could just do:
class Example { public: void foo ( ) { } };
// elsewhere...
singleton < Example >::pointer ptr; ptr->foo ( );
I believe (as in "I didn´t tested it" :) that using it in this way would allow multiple instances of Example? For example? singleton<Example>::pointer ptr; Example other; Sérgio

Sérgio Vale e Pace wrote:
On Sun, 13 Feb 2005 19:20:07 -0500, Jason Hise <chaos@ezequal.com> wrote:
I recently discovered that my singleton could potentially be used in a way other than as a base class. For example, to create and use a singleton instance of a class which could have other ordinary instances as well, one could just do:
class Example { public: void foo ( ) { } };
// elsewhere...
singleton < Example >::pointer ptr; ptr->foo ( );
I believe (as in "I didn´t tested it" :) that using it in this way would allow multiple instances of Example? For example?
singleton<Example>::pointer ptr; Example other;
This is not a problem. The designer of Example does permit such use: Example a; Example b;

On Mon, 14 Feb 2005 16:00:08 +0200, Peter Dimov <pdimov@mmltd.net> wrote:
Sérgio Vale e Pace wrote:
On Sun, 13 Feb 2005 19:20:07 -0500, Jason Hise <chaos@ezequal.com> wrote:
I recently discovered that my singleton could potentially be used in a way other than as a base class. For example, to create and use a singleton instance of a class which could have other ordinary instances as well, one could just do:
class Example { public: void foo ( ) { } };
// elsewhere...
singleton < Example >::pointer ptr; ptr->foo ( );
I believe (as in "I didn´t tested it" :) that using it in this way would allow multiple instances of Example? For example?
singleton<Example>::pointer ptr; Example other;
This is not a problem. The designer of Example does permit such use:
Example a; Example b;
Sorry for the ignorance, but then what´s the point of using the singleton if Example is not suposed to be a singleton?

Sérgio Vale e Pace wrote:
On Mon, 14 Feb 2005 16:00:08 +0200, Peter Dimov <pdimov@mmltd.net> wrote:
This is not a problem. The designer of Example does permit such use:
Example a; Example b;
Sorry for the ignorance, but then what´s the point of using the singleton if Example is not suposed to be a singleton?
A class that supports an arbitrary number of instances also supports a single instance. It's not a programming error to use one instance of Example as a "singleton" to solve the initialization order problem (the only legitimate use of the "singleton pattern", in my opinion). The reverse, of course, is not true. If a class only supports a single instance the programmer shouldn't be allowed to create multiple instances.

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Peter Dimov Sent: Monday, February 14, 2005 10:12 AM To: boost@lists.boost.org Subject: Re: [boost] singleton usage
as a "singleton" to solve the initialization order problem (the only legitimate use of the "singleton pattern", in my opinion).
Could you please elaborate? Why do you consider this is the only legitimate use for this pattern? Thanks in advance. Best regards Jorge

Jorge Lodos wrote:
as a "singleton" to solve the initialization order problem (the only legitimate use of the "singleton pattern", in my opinion).
Could you please elaborate? Why do you consider this is the only legitimate use for this pattern? Thanks in advance.
A singleton is simply a glorified wrapper over several global variables and functions. There is little difference between Singleton::instance().f(); and Singleton::f(); where the second Singleton is a namespace. The global variables don't become any less "evil" when they are made members of a singleton class. When a class represents an out-of-program entity that, by its nature, has a single instance, this class can be flattened into functions. This isn't black and white, of course; today's code may treat the video card as a singleton, but tomorrow's computers may add multiple video card support. In this case I still prefer something along the lines of VideoCard & get_video_card( int id ); // noncopyable or maybe even video_card_ref get_video_card( int id ); // reference copy semantics instead of the "multisingleton" way of VideoCard::instance( id ). But "true" singletons are either crippled ordinary classes or collections of global functions (under the assumption that there are no initialization order issues, of course).

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Peter Dimov Sent: Monday, February 14, 2005 2:38 PM To: boost@lists.boost.org Subject: Re: [boost] singleton usage
A singleton is simply a glorified wrapper over several global variables and functions. There is little difference between
Singleton::instance().f();
and
Singleton::f();
where the second Singleton is a namespace. The global variables don't become any less "evil" when they are made members of a singleton class.
When a class represents an out-of-program entity that, by its nature, has a single instance, this class can be flattened into functions.
This isn't black and white, of course; today's code may treat the video card as a singleton, but tomorrow's computers may add multiple video card support. In this case I still prefer something along the lines of
VideoCard & get_video_card( int id ); // noncopyable
or maybe even
video_card_ref get_video_card( int id ); // reference copy semantics
instead of the "multisingleton" way of
VideoCard::instance( id ).
But "true" singletons are either crippled ordinary classes or collections of global functions (under the assumption that there are no initialization order issues, of course).
Thank you for your comments. I agree with everything you said and try to avoid singletons in the first place. However, I have a practical problem that I have been able to "solve" only thru singletons. In a header only library that uses a class factory, the registration of objects with the factory is performed in a constructor of an object inside an anonymous namespace. Since the header may be #included more that once, I made those objects singletons to avoid multiple registration. The singleton::instance method may be called more that once without need, that's why I put "solve" in quotes. Since the object is inside an anonymous namespace, I can not use templates, which never get instantiated. If you or anyone else have a suggestion that allows for automatic registration without using singletons please share it :-) I would like to keep the anonymous namespace, but if there is a nice solution that requires a named one then I would adopt it. Thanks in advance. Best regards Jorge

Jorge Lodos wrote:
Thank you for your comments. I agree with everything you said and try to avoid singletons in the first place. However, I have a practical problem that I have been able to "solve" only thru singletons. In a header only library that uses a class factory, the registration of objects with the factory is performed in a constructor of an object inside an anonymous namespace. Since the header may be #included more that once, I made those objects singletons to avoid multiple registration. The singleton::instance method may be called more that once without need, that's why I put "solve" in quotes. Since the object is inside an anonymous namespace, I can not use templates, which never get instantiated. If you or anyone else have a suggestion that allows for automatic registration without using singletons please share it :-)
Can you use something like the following: class auto_reg { static int count_; auto_reg() { if( ++count_ == 1 ) register(); } ~auto_reg() { if( --count_ == 0 ) unregister(); } }; int auto_reg::count_; To make it header-only use the template<class _ = void> trick.

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Peter Dimov Sent: Monday, February 14, 2005 4:27 PM To: boost@lists.boost.org Subject: Re: [boost] singleton usage
Jorge Lodos wrote:
Thank you for your comments. I agree with everything you said and try to avoid singletons in the first place. However, I have a practical problem that I have been able to "solve" only thru singletons. In a header only library that uses a class factory, the registration of objects with the factory is performed in a constructor of an object inside an anonymous namespace. Since the header may be #included more that once, I made those objects singletons to avoid multiple registration. The singleton::instance method may be called more that once without need, that's why I put "solve" in quotes. Since the object is inside an anonymous namespace, I can not use templates, which never get instantiated. If you or anyone else have a suggestion that allows for automatic registration without using singletons please share it :-)
Can you use something like the following:
class auto_reg { static int count_;
auto_reg() { if( ++count_ == 1 ) register(); }
~auto_reg() { if( --count_ == 0 ) unregister(); } };
int auto_reg::count_;
To make it header-only use the template<class _ = void> trick.
Well, this sure would replace the singletons, thanks! Still, the class constructor will be called more than once. I was hoping there was a solution where this wouldn't happen. Some template magic, I guess :-). Thanks again! Jorge Jorge

From everything I know, cin, cout, cerr, and clog are simply global variables that live in namespace std. Does this mean that the following code is dangerous? class Log { public: Log ( ) { std::clog << "Log created\n"; } ~ Log ( ) { std::clog << "Log destroyed\n"; } } global_log; If so, (and I know this is presumptuous, so strictly hypothetically speaking) could these four standard streams benefit by becoming singletons? Just a thought experiment... -Jason

On Tue, 15 Feb 2005 23:11:49 -0500, Jason Hise <chaos@ezequal.com> wrote:
From everything I know, cin, cout, cerr, and clog are simply global variables that live in namespace std. Does this mean that the following code is dangerous?
AFAIK yes. If you have a singleton object that is being destroyed at exit, it is possible that cin/cout/clog etc have been closed before Log::~Log is called.
class Log { public: Log ( ) { std::clog << "Log created\n"; } ~ Log ( ) { std::clog << "Log destroyed\n"; } } global_log;
If so, (and I know this is presumptuous, so strictly hypothetically speaking) could these four standard streams benefit by becoming singletons? Just a thought experiment...
-- Caleb Epstein caleb dot epstein at gmail dot com

On Tue, Feb 15, 2005 at 11:11:49PM -0500, Jason Hise wrote:
From everything I know, cin, cout, cerr, and clog are simply global variables that live in namespace std. Does this mean that the following code is dangerous?
class Log { public: Log ( ) { std::clog << "Log created\n"; } ~ Log ( ) { std::clog << "Log destroyed\n"; } } global_log;
The standard streams are meant to be available for users at any time. Quite how implementations are supposed to achieve this isn't mandated: http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#369 But I think the intention is that the code above is legal and safe. See 27.3/2 jon

From: Jason Hise <chaos@ezequal.com>
Pavel Vozenilek wrote:
The use case is a legacy code that accepts only bald pointer.
A singleton may have function unsafe_get(). The object would be instantiated if not already.
Code using its result will promise not to destroy given object.
In such cases, I wonder if it might be best for the user's singleton to provide the function:
class Example : public singleton < Example > { // protected ctor and dtor public: Example * unsafe_get ( ) { return this; } };
That way not all singleons would need to suffer the 'security hole' just because a few need it.
That's definitely better. You don't want to make it pretty when someone adds this feature. However, given that the need for this behavior might be just common enough to make this addition to every Singleton type too much pain, how about another class template: template <typename T> class unsafe_singleton : public singleton<T> { public: //! WARNING: Do not delete the returned pointer! T * unsafe_get() { return this; } }; -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Rob Stewart wrote:
That's definitely better. You don't want to make it pretty when someone adds this feature. However, given that the need for this behavior might be just common enough to make this addition to every Singleton type too much pain, how about another class template:
template <typename T> class unsafe_singleton : public singleton<T> { public: //! WARNING: Do not delete the returned pointer! T * unsafe_get() { return this; } };
That's manageable, I can add that. -Jason

"Jason Hise" wrote:
Rob Stewart wrote:
template <typename T> class unsafe_singleton : public singleton<T> { public: //! WARNING: Do not delete the returned pointer! T * unsafe_get() { return this; } };
That's manageable, I can add that.
Maybe function template<.....> T* unsafe_get_pointer(singleton<T>::pointer&) { ... } would be enough. Having one more class for just one function feels as overkill. Local need for raw pointer should not mean possibly global change in design. /Pavel

Pavel Vozenilek wrote:
Maybe function
template<.....> T* unsafe_get_pointer(singleton<T>::pointer&) { ... }
would be enough. Having one more class for just one function feels as overkill.
Local need for raw pointer should not mean possibly global change in design.
/Pavel
I'm terribly torn on this issue. Use of a raw singleton pointer is dangerous if it remains in use for a long period of time, specifically long enough for the instance to have a possibility of being destroyed. If the singleton uses a real locking policy the code using the raw pointer would have to lock the operations manually. On the other hand, a raw pointer is the only really feasible way to pass a singleton pointer as a pointer to a non singleton base class. Example: class LoggerBase { public: virtual void Log ( const char * msg ) = 0; }; class GlobalLog : public singleton < GlobalLog >, public LoggerBase { public: virtual void Log ( const char * msg ) { // write to file or something } }; void PerformOperation ( vector < LoggerBase * > listeners, /*other operands*/ ) { if ( shit_happens ) { // use lambda and for_each to write a message to each log in listeners // (I don't know the lambda library so I can't write this code myself. I should take next weekend to learn it, it looks really handy) } } Thus, at this point my thought is that the C++ motto is 'trust the programmer', so I'm thinking I should just provide the unsafe_raw_ptr ( ) member in the singleton, surround it with comments in all caps, and document the heck out of it. -Jason

From: Jason Hise <chaos@ezequal.com>
Pavel Vozenilek wrote:
template<.....> T* unsafe_get_pointer(singleton<T>::pointer&) { ... }
would be enough. Having one more class for just one function feels as overkill.
Local need for raw pointer should not mean possibly global change in design.
Good idea Pavel. That is simpler and is easy to grep for in one's code base, just like "reinterpret_cast."
I'm terribly torn on this issue.
Use of a raw singleton pointer is dangerous if it remains in use for a long period of time, specifically long enough for the instance to have a possibility of being destroyed. If the singleton uses a real locking policy the code using the raw pointer would have to lock the operations manually.
The function's name is "unsafe_get_pointer." Caveat emptor. You document the problems, such as undefined behavior due to dereferencing the returned pointer after the Singleton has been destroyed, and let the programmer deal with the consequences.
On the other hand, a raw pointer is the only really feasible way to pass a singleton pointer as a pointer to a non singleton base class. Example: [snipped] Thus, at this point my thought is that the C++ motto is 'trust the programmer', so I'm thinking I should just provide the unsafe_raw_ptr ( ) member in the singleton, surround it with comments in all caps, and document the heck out of it.
Putting the function in the class definition raises awareness of it and lends it more credibility as a reasonable use of the class. Making it a non-member function keeps it rather separate and gives it a bit of that "workaround" flavor. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;
participants (9)
-
Caleb Epstein
-
Dave Handley
-
Jason Hise
-
Jonathan Wakely
-
Jorge Lodos
-
Pavel Vozenilek
-
Peter Dimov
-
Rob Stewart
-
Sérgio Vale e Pace