7 ms·
C++11: A generic singleton
- vjeux 14y agoNice use of perfect forwarding!
- vadeo 14y agoCool article
- btilly 14y agoThis is interesting. But be aware that singletons are to be regarded cautiously for all of the reasons that, say, global variables are.
- klodolph 14y agoPlus some additional reasons: if a singleton is initialized on first use, it might be hard to reason about which kind of environment exists when it is initialized -- what locks are held, etc.
- quotemstr 14y agoNo no no no no. This approach still needs heap allocation, and you still need to chase a pointer for every access to your singleton. That's silly. There's a much better way. Here it is, roughly speaking. template<typename T> struct singleton_bss { T& get() { return * ((T*) &this->buffer[0]); } void init(T&& value) { new ( (T*) &this->buffer[0] ) T(std::forward<T> (value)); } union { char buffer[sizeof(T)]; long align; // adjust to taste }; }; singleton_bss<mything> g_thing; This approach has the huge advantage of not doing any heap allocation. The storage for g_thing lives directly in bss, the portion of your processes' address space initialized by the operating system. g_thing.init() cannot fail if T's constructor is non-throwing --- singleton_bss allocates no memory! Access to g_thing is much more efficient than access to a typical singleton. There's no pointer-to-the-instance stored in the singleton, so there's no pointer chasing. Access to g_thing is exactly as efficient as access to a plain global variable, which is as efficient as variable access can be. You can trivially construct a version of singleton_bss that does lazy initialization, takes multiple parameters, destroys the object on module unload, and so on.
- keveman 14y agoHere is the C++11 way of specifying alignment : alignas(T) char buffer[sizeof(T)]; Or better still, just use the unrestricted union feature : union { T t; }; Just use &t in place of buffer.
- quotemstr 14y agoThanks for the tip --- alignas slipped my mind. The compiler I use for most of my work doesn't yet support alignas (or unrestricted unions). I believe a VC++-specific equivalent would for the former trick would be __declspec(align(__alignof(T))).
- keveman 14y agoYeah, you are right, alignas is still unsupported in many compilers. clang 3.2 supports it. However, unrestricted unions has been supported in many compilers for a long time now. I would use that in this case, since you already know the type 'T'.
- zerohp 14y agoI prefer the answer given here: http://stackoverflow.com/questions/1463707/c-singleton-vs-global-static-object http://stackoverflow.com/questions/1463707/c-singleton-vs-gl...
- pfedor 14y agoThis is wrong for reasons given here: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Static_and_Global_Variables http://google-styleguide.googlecode.com/svn/trunk/cppguide.x...
- pmelendez 14y agoI am not sure if that applies here... Static objects introduce hard to find bugs because you can't figure out the order of instantiation... Over here there is just one unique instance so you know exactly where it was instantiated.
- pfedor 14y agoBut that unique instance is presumably referenced by other objects which may want to use it as part of their own shut down logic, at which point it might no longer exist. (And things get only worse in the presence of threads.)
- deleted 14y ago[deleted]
- pmelendez 14y agoSorry I read it again (the first time I was reading it on my phone) and I thought we were discussing about Meyers singleton: Singleton & theSingleton() { static Singleton instance; return instance; } Which in the proper context is perfectly fine. This is wrong: class myclass { // can have state // ... public static myclass m = new myclass(); // globally accessible static instance, which can have state } and the first link itself explain why.
- 02f39nrca 14y agoExperience shows the singleton pattern is more trouble than it's worth. Explicitly initialise shared resources in one thread either from main, or if you're writing a shared library, the explicit initialisation function you'll have to add anyway if the library is properly designed.
- RomP 14y agoone word: synchronization
- skrebbel 14y agoHooray, now you can use anti-patterns in a generic way! I have yet to find a single good reason for having singletons, other than dealing with legacy code that has them (and, potentially, logging). Singletons are the worst anti-pattern out there, removing any sense of testability and reconfiguration in your project. The only good-ish argument for singletons (other than, again, dealing with legacy code that has them) is that inversion of control requires so many objects to be passed around to constructors. This argument becomes invalid once you realise that many-instances-needed-on-constructors is in fact a warning sign that your classes are getting too tightly bound. Draw out the entities again and see where you can abstract or generalize.
- pmelendez 14y ago"I have yet to find a single good reason for having singletons, other than dealing with legacy code that has them (and, potentially, logging). Singletons are the worst anti-pattern out there, removing any sense of testability and reconfiguration in your project" I think you are being a bit dogmatic here. There are good uses for singleton classes in single threaded applications that don't use unit tests (i.e most mobile games). People should just think and evaluate each case instead or tagging stuff as pattern or anti-pattern. Am I the only one who think that both (pattern and anti-pattern) are evil? This reminds me a lot all the goto controversy.
- malkia 14y agoBy this logic anything is acceptable.
- bmohlenhoff 14y agoAnything is acceptable, it's all a function of the domain.
- pmelendez 14y agoIf there is a good use for it... Why not? In medicine stuff that normally hurt you is used to cure you as well... You just need to know when and how to use it.
- enki42 14y agoHi everyone! I'm the author of this blog. I agree with most of you that Singleton can lead to destroy a design. I just think that we should not ban something globally, and I'm sure that this (anti-?)pattern can be useful sometimes. The aim of this post was not to encourage people to use Singleton, but to show how C++11 can improve our way to write classical code. I just took a simple example of singleton.
- malkia 14y agoA global variable is more useful than singleton, since it comes with no battery, plan or pretense. Singleton at minimal requires thread-safety, and that comes very hard. It also contradicts with itself when a singleton is made thread-specific variable (TLS) - because it's singleton / thread, but not per process.
- enki42 14y agoWhy should a Singleton be thread safe? Nothing says that it will be used in a multi-threaded environment... For me a Singleton must fulfill the specification given by the Gang of Four. I'm not saying that it should not be thought thread safe, I just say that it's not the point here.
- malkia 14y agoWhat is better then: g_current_context->Something() or g_current_context::singleton()->Something() Because I can set in a special place g_current_context to the initial value knowing it would be safe to do so, while the singleton is going to set it, once it's first needed, and that might not be appropriate. The problem with singleton's is that initialization is not controlled - what if the singleton is for the first time called from function that already ate too much stack, and now the initialization routine for the singleton wants more? What if it was called from thread? Or interrupt routine? Or during time sensitive operation that needs to finish on-time (like something producing audio samples, which called every 5ms, need to finish in 2-3ms). Or callback that needs to return as soon as possible to the caller. How are you going to deal with it then? It's much better to be explicit in this case, have a safe place, where no threads are created yet and initialize it, without any protection needed, and then use it as global variable. Even better, if possible, put all these variables in page (if the OS allows) - initialize them, and then make them READONLY - to know that's not going to change.
- shanemhansen 14y agoI have a lot of respect for those C++ guys/girls. Frankly, If I had to think this hard to get my code written, I wouldn't be writing very much of it. Thank heavens for small languages that leave my brain cycles to think about solving other problems. But don't listen to me, listen to Linus and Rob Pike. http://commandcenter.blogspot.com/2012/06/less-is-exponentially-more.html http://commandcenter.blogspot.com/2012/06/less-is-exponentia... http://harmful.cat-v.org/software/c++/linus http://harmful.cat-v.org/software/c++/linus
- stephen_g 14y agoDo you mean a small language such as C? Because I disagree completely. Whenever I use C, I always seem to find myself wishing for C++'s string class, the STL containers and exception handling... There are libraries for C to get containers and things but C interfaces tend to be uglier (in my opinion) and it's annoying to have to use a lot of 3rd party stuff to get things that come with C++. Just because C++ has a ton of other features (many of which are pretty easy to use incorrectly if you don't know how) doesn't mean you have to use all of them.
- shanemhansen 14y agoC is small and beautiful, but my preference is more along the lines of go, or maybe objective-c or d.