No 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.
Hooray, 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.
"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.
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.
Do 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.
Experience 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.
Plus 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.
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.
A 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.
[+] [-] quotemstr|13 years ago|reply
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|13 years ago|reply
[+] [-] skrebbel|13 years ago|reply
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|13 years ago|reply
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.
[+] [-] shanemhansen|13 years ago|reply
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-exponentia...
http://harmful.cat-v.org/software/c++/linus
[+] [-] stephen_g|13 years ago|reply
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.
[+] [-] 02f39nrca|13 years ago|reply
[+] [-] btilly|13 years ago|reply
But be aware that singletons are to be regarded cautiously for all of the reasons that, say, global variables are.
[+] [-] klodolph|13 years ago|reply
[+] [-] enki42|13 years ago|reply
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|13 years ago|reply
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.
[+] [-] zerohp|13 years ago|reply
http://stackoverflow.com/questions/1463707/c-singleton-vs-gl...
[+] [-] pfedor|13 years ago|reply
[+] [-] vjeux|13 years ago|reply
[+] [-] vadeo|13 years ago|reply
[+] [-] RomP|13 years ago|reply