Edit: From another question I provided an answer that has links to a lot of questions/answers about singletons: More info about singletons here:
So I have read th
Singletons give you the ability to combine two bad traits in one class. That's wrong in pretty much every way.
A singleton gives you:
Number one is straightforward. Globals are generally bad. We should never make objects globally accessible unless we really need it.
Number two may sound like it makes sense, but let's think about it. When was the last time you **accidentally* created a new object instead of referencing an existing one? Since this is tagged C++, let's use an example from that language. Do you often accidentally write
std::ostream os;
os << "hello world\n";
When you intended to write
std::cout << "hello world\n";
Of course not. We don't need protection against this error, because that kind of error just doesn't happen. If it does, the correct response is to go home and sleep for 12-20 hours and hope you feel better.
If only one object is needed, simply create one instance. If one object should be globally accessible, make it a global. But that doesn't mean it should be impossible to create other instances of it.
The "only one instance is possible" constraint doesn't really protect us against likely bugs. But it does make our code very hard to refactor and maintain. Because quite often we find out later that we did need more than one instance. We do have more than one database, we do have more than one configuration object, we do want several loggers. Our unit tests may want to be able to create and recreate these objects every test, to take a common example.
So a singleton should be used if and only if, we need both the traits it offers: If we need global access (which is rare, because globals are generally discouraged) and we need to prevent anyone from ever creating more than one instance of a class (which sounds to me like a design issue). The only reason I can see for this is if creating two instances would corrupt our application state - probably because the class contains a number of static members or similar silliness. In which case the obvious answer is to fix that class. It shouldn't depend on being the only instance.
If you need global access to an object, make it a global, like std::cout
. But don't constrain the number of instances that can be created.
If you absolutely, positively need to constrain the number of instances of a class to just one, and there is no way that creating a second instance can ever be handled safely, then enforce that. But don't make it globally accessible as well.
If you do need both traits, then 1) make it a singleton, and 2) let me know what you need that for, because I'm having a hard time imagining such a case.
Singletons are handy when you've got a lot code being run when you initialize and object. For example, when you using iBatis when you setup a persistence object it has to read all the configs, parse the maps, make sure its all correct, etc.. before getting to your code.
If you did this every time, performance would be much degraded. Using it in a singleton, you take that hit once and then all subsequent calls don't have to do it.
But when I need something like a Singleton, I often end up using a Schwarz Counter to instantiate it.
- How do you implement a Singleton correctly
There's one issue I've never seen mentioned, something I ran into at a previous job. We had C++ singletons that were shared between DLLs, and the usual mechanics of ensuring a single instance of a class just don't work. The problem is that each DLL gets its own set of static variables, along with the EXE. If your get_instance function is inline or part of a static library, each DLL will wind up with its own copy of the "singleton".
The solution is to make sure the singleton code is only defined in one DLL or EXE, or create a singleton manager with those properties to parcel out instances.
If you are the one who created the singleton and who uses it, dont make it as singleton (it doesn't have sense because you can control the singularity of the object without making it singleton) but it makes sense when you a developer of a library and you want to supply only one object to your users (in this case you are the who created the singleton, but you aren't the user).
Singletons are objects so use them as objects, many people accesses to singletons directly through calling the method which returns it, but this is harmful because you are making your code knows that object is singleton, I prefer to use singletons as objects, I pass them through the constructor and I use them as ordinary objects, by that way, your code doesn't know if these objects are singletons or not and that makes the dependencies more clear and it helps a little for refactoring ...
Below is the better approach for implementing a thread safe singleton pattern with deallocating the memory in destructor itself. But I think the destructor should be an optional because singleton instance will be automatically destroyed when the program terminates:
#include<iostream>
#include<mutex>
using namespace std;
std::mutex mtx;
class MySingleton{
private:
static MySingleton * singletonInstance;
MySingleton();
~MySingleton();
public:
static MySingleton* GetInstance();
MySingleton(const MySingleton&) = delete;
const MySingleton& operator=(const MySingleton&) = delete;
MySingleton(MySingleton&& other) noexcept = delete;
MySingleton& operator=(MySingleton&& other) noexcept = delete;
};
MySingleton* MySingleton::singletonInstance = nullptr;
MySingleton::MySingleton(){ };
MySingleton::~MySingleton(){
delete singletonInstance;
};
MySingleton* MySingleton::GetInstance(){
if (singletonInstance == NULL){
std::lock_guard<std::mutex> lock(mtx);
if (singletonInstance == NULL)
singletonInstance = new MySingleton();
}
return singletonInstance;
}
Regarding the situations where we need to use singleton classes can be- If we want to maintain the state of the instance throughout the execution of the program If we are involved in writing into execution log of an application where only one instance of the file need to be used....and so on. It will be appreciable if anybody can suggest optimisation in my above code.