
Gregory Dai ha escrito:
On 5/8/07, Medland, Thomas M <thomas.medland@lehman.com> wrote:
Hi,
I have just moved company and in my old company I used to use a RogueWave singleton class. I was looking to use the boost singleton class. However after looking at the implementation I saw there was no private default copy constructor or assignment operator. Does this not mean that I could create multiple instances of my singleton via assignment or some other form of copying? I saw some discussion of a better singleton representation in boost and I was wondering what the status of this was, and I was also wondering what other people use for their singletons?
Thanks Tom
Well, I use the following. It's pretty simple and it works.
[...] Hello Greg, I think there's a potential problem with your static_instantiation policy (or at least a limitation in applicability) due to its relying on the class template static member static_instantiation::holder<T>::instance_s. As this member is initialized only once (for a given T), the initialization will take place in some of the translation units, but there's no way to say which one, and the standard cannot not guarantee that the initialization will occur before the first use of static_instantiation::holder<T> if that use happens at dynamic initialization time. The following shows the problem: ***foo.hpp*** #include <singleton.hpp> struct foo { foo():initialized(true){} bool initialized; }; typedef ste::pattern::singleton< foo, ste::pattern::static_instantiation
foo_singleton_type;
***tunit1.cpp*** #include "foo.hpp" bool b1=foo_singleton_type::instance()->initialized; ***tunit2.cpp*** #include "foo.hpp" bool b2=foo_singleton_type::instance()->initialized; ***main.cpp*** #include <iostream> extern bool b1; extern bool b2; int main() { std::cout<<"b1: "<<b1<<std::endl; std::cout<<"b2: "<<b1<<std::endl; } ****** I've tried the program composed of main.cpp, tunit1.cpp and tunit2.cpp in GCC 3.2 and the program output is not always what one'd expect, but rather it depends haphazardly on the order the translation units are compiled: g++ ... main.cpp tunit1.cpp tunit2.cpp output: b1: 1 b2: 1 g++ ... main.cpp tunit2.cpp tunit1.cpp output: b1: 0 b2: 0 g++ ... tunit1.cpp main.cpp tunit2.cpp output: b1: 1 b2: 1 g++ ... tunit1.cpp tunit2.cpp main.cpp output: b1: 1 b2: 1 g++ ... tunit2.cpp main.cpp tunit1.cpp output: b1: 0 b2: 0 g++ ... tunit2.cpp tunit1.cpp main.cpp output: b1: 0 b2: 0 You can solve this by combining a Meyers singleton with some static initialization forcing technique: class static_instantiation { template <typename T> struct init_forcer { init_forcer() { T* p; static_instantiation::make<T>(p); } void do_nothing(){} static init_forcer<T> init_forcer_s; }; protected: template <typename T> static void make(T*& p) { init_forcer<T>::init_forcer_s.do_nothing(); static T instance; p = &instance; } }; template <typename T> typename static_instantiation::init_forcer<T>::init_forcer static_instantiation::init_forcer<T>::init_forcer::init_forcer_s; This technique is used for instance by Boost.Pool, see boost/pool/detail/singleton.hpp. Hope this helps, Joaquín M López Muñoz Telefónica, Investigación y Desarrollo