using weak_ptr and shared_ptr for singleton
Hello!
I do some experiments on shared_ptr and weak_ptr. So I tried to use them
for a singleton-class, which does not need an explicit
singleton::release_instance method. The singleton-instance will be
destroyed everytime the last external shared_ptr holding the instance
goes out of scope. Is this a valid usage for weak_ptr? Are there any
traps I do not see using these smart_ptrs in this context?
The drawback of using shared_ptr with singleton is the need for a public
destructor. But this is dangerous....it is possible to write
singleton::singleton_ptr first_ptr = singleton::instance();
delete first_ptr.get();
Declaring the destructor as private is only possible when defining
boost::checked_delete as friend of the singleton-class.
( there is a thread on comp.lang.c++.moderated with the topic
'specialization of function template as friend with MSVC6SP5 not
possible' which deals with this problem of friendship... )
But then it is still possible to write the following code
singleton::singleton_ptr first_ptr = singleton::instance();
boost:checked_delete( first_ptr.get() );
OK, it's very unlikely to do it by chance, but it is possible.
Is there a way to allow destruction of the instance only to shared_ptr?
<code>
#include
From: "Stephan Born"
Hello!
I do some experiments on shared_ptr and weak_ptr. So I tried to use them for a singleton-class, which does not need an explicit singleton::release_instance method. The singleton-instance will be destroyed everytime the last external shared_ptr holding the instance goes out of scope. Is this a valid usage for weak_ptr? Are there any traps I do not see using these smart_ptrs in this context?
The drawback of using shared_ptr with singleton is the need for a public destructor. But this is dangerous....it is possible to write
singleton::singleton_ptr first_ptr = singleton::instance(); delete first_ptr.get();
Declaring the destructor as private is only possible when defining boost::checked_delete as friend of the singleton-class. ( there is a thread on comp.lang.c++.moderated with the topic 'specialization of function template as friend with MSVC6SP5 not possible' which deals with this problem of friendship... ) But then it is still possible to write the following code
singleton::singleton_ptr first_ptr = singleton::instance(); boost:checked_delete( first_ptr.get() );
OK, it's very unlikely to do it by chance, but it is possible.
Is there a way to allow destruction of the instance only to shared_ptr?
Your class isn't a "canonical" singleton since those have one instance per program; yours has one instance at a time. That aside, there are two ways to prohibit deletion: 1. Make the destructor protected and return an instance of a derived class: X.hpp: class X { protected: ~X(); public: shared_ptr<X> instance(); }; X.cpp: class X_impl: public X // not visible to clients { }; shared_ptr<X> X::instance() { return shared_ptr<X>(new X_impl); } 2. Use a custom private deallocator: class X { private: ~X(); static void destroy(X * p) { delete p; } public: shared_ptr<X> instance() { return shared_ptr<X>(new X, X::destroy); } };
Stephan Born wrote:
Hello!
I do some experiments on shared_ptr and weak_ptr. So I tried to use them for a singleton-class, which does not need an explicit singleton::release_instance method. The singleton-instance will be destroyed everytime the last external shared_ptr holding the instance goes out of scope. Is this a valid usage for weak_ptr? Are there any traps I do not see using these smart_ptrs in this context?
Within the singleton class I hold the instance with a shared_ptr. I consider this the best option, as it guarantees the correct order of destruction when a singleton depends on another one.
The drawback of using shared_ptr with singleton is the need for a public destructor. But this is dangerous....it is possible to write
singleton::singleton_ptr first_ptr = singleton::instance(); delete first_ptr.get();
You should rely on the constructor that takes an additional deleter
argument, something like (not compiled and almost certainly incomplete
and incorrect):
class SingletonDeleter {
friend class shared_ptr<Singleton>;
operator() (Singleton *p) { delete p; }
};
class Singleton {
friend class SingletonDeleter;
public:
shared_ptr
Declaring the destructor as private is only possible when defining boost::checked_delete as friend of the singleton-class. [...] But then it is still possible to write the following code
singleton::singleton_ptr first_ptr = singleton::instance(); boost:checked_delete( first_ptr.get() );
OK, it's very unlikely to do it by chance, but it is possible.
Moreover, you rely on what should be an implementation detail. Cheers, Nicola Musatti
Nicola Musatti wrote:
Within the singleton class I hold the instance with a shared_ptr. I consider this the best option, as it guarantees the correct order of destruction when a singleton depends on another one.
But I *want* it to be delete automagically...and I do not see the danger: if there is a dependent second_singleton it would hold a shared_ptr to my singleton, and singleton would not be destroyed before second_singleton is destroyed by its own. Maybe it should be made an option by using policies....but I really do not the danger.
You should rely on the constructor that takes an additional deleter argument, something like (not compiled and almost certainly incomplete and incorrect):
class SingletonDeleter { friend class shared_ptr<Singleton>; operator() (Singleton *p) { delete p; } };
class Singleton { friend class SingletonDeleter; public: shared_ptr
instance() { if ( inst == 0 ) inst = shared_ptr ( new Singleton,SingletonDeleter()); return inst; } }; typedef shared_ptr
SingletonPtr;
Yes, I fear it *is* incorrect ;) look at the bottom of the posting for my implelentation
Declaring the destructor as private is only possible when defining boost::checked_delete as friend of the singleton-class.
[...]
But then it is still possible to write the following code
singleton::singleton_ptr first_ptr = singleton::instance(); boost:checked_delete( first_ptr.get() );
OK, it's very unlikely to do it by chance, but it is possible.
Moreover, you rely on what should be an implementation detail.
OK, I hope that this will be the correct way:
* I do not rely on implementation-detail ( make boost::checked_delete a
friend )
* I provide my own deleter-functor
<code>
#include
Stephan Born wrote:
Nicola Musatti wrote:
Within the singleton class I hold the instance with a shared_ptr. I consider this the best option, as it guarantees the correct order of destruction when a singleton depends on another one.
But I *want* it to be delete automagically...and I do not see the danger: if there is a dependent second_singleton it would hold a shared_ptr to my singleton, and singleton would not be destroyed before second_singleton is destroyed by its own. Maybe it should be made an option by using policies....but I really do not the danger.
I think we mean the same thing. The only thing I was pointing out is that my static data member that holds the pointer is a shared_ptr and not a weak_ptr. This is because I want my singleton instance to survive even if sometime during execution it isn't used by other objects, rather than be recreated each time as yours is. Cheers, Nicola Musatti
From: "Stephan Born"
Declaring the destructor as private is only possible when defining boost::checked_delete as friend of the singleton-class. ( there is a thread on comp.lang.c++.moderated with the topic 'specialization of function template as friend with MSVC6SP5 not possible' which deals with this problem of friendship... )
I missed that thread... no 'boost', 'shared_ptr' or 'checked_delete' in the subject. :-) Anyway, making boost::checked_delete a friend - even if you could do it ;-) - is not guaranteed to work. boost::shared_ptr isn't required to use boost::checked_delete.
Peter Dimov schrieb: [snip]
I missed that thread... no 'boost', 'shared_ptr' or 'checked_delete' in the subject. :-)
Anyway, making boost::checked_delete a friend - even if you could do it ;-) - is not guaranteed to work. boost::shared_ptr isn't required to use boost::checked_delete.
Yes, you are right....I'm still learning ;) Thank you all Regards, Stephan -- --------------------------------------------------------------- Dipl.-Inf. (FH) Stephan Born | beusen Solutions GmbH fon: +49 30 549932-0 | Landsberger Allee 366 fax: +49 30 549932-21 | 12681 Berlin mailto:stephan.born@beusen.de | Germany --------------------------------------------------------------- PGP-Key verfügbar | PGP-Key available ---------------------------------------------------------------
participants (3)
-
Nicola Musatti
-
Peter Dimov
-
Stephan Born