Bring you two different implantation of singleton design pattern:
class SingletonCSM;
using SingletonCSMSp = std::shared_ptr < SingletonCSM > ;
class SingletonCSM
{
public:
~SingletonCSM() { spInstance = nullptr; }
static SingletonCSMSp GetInstance()
{
if (!spInstance)
spInstance = std::make_shared<SingletonCSM>();
return spInstance;
}
private:
SingletonCSM() {}
// will be intilized in the cpp: SingletonCSMSp SingletonCSM::spInstance = nullptr;
static SingletonCSMSp spInstance;
};
class SingletonFSV;
using SingletonFSVSp = std::shared_ptr < SingletonFSV > ;
class SingletonFSV
{
public:
~SingletonFSV() {}
static SingletonFSVSp GetInstance()
{
static SingletonFSVSp spInstance = std::make_shared<SingletonFSV>();
return spInstance;
}
private:
SingletonFSV() {}
};
I always use the first impl. SingletonCSM
. I came across, in our code, an impl. like SingletonFSV
Class SingletonFSV
was implemented as a part of a DLL project. This DLL, compiled in VS 2013
, is loaded in memory by an exe file and run.
I've upgrade my VS
to VS 2015
, compiled the DLL project and run the exe. All of a sudden, it crashed. While debugging, I've notice that the crash happened in the DLL itself. make_shared
called withing GetInstance()
returned nullptr
and naturally caused segmentation fault.
I've changed SingletonFSV
impl. to SingletonCSM
and the crash stopped. make_shared
returned a valid pointer and the problem was solved.
I just don't understand what was the problem and why was it solved?
When you put a static
variable inside a function it is created the first time the function is called so it is guaranteed to have been instantiated to all callers of the function.
Members that are declared static
could be instantiated before or after you call your function because the initialization order between translation units is undefined. So a global object or static
object could try to access a static member before its been initialized by the runtime system.
So to your questions:
- Can we consider both impl. as a valid impl. of the design pattern?
- Are both, functionally, the same?
No. Using a static
member is dangerous because a caller to SingletonCSM::GetInstance()
can access a non-created object if the nullptr
initialization has not taken place before the call. The static
function method is the recommended method because it guarantees initialization has completed for every caller.
I just don't understand what was the problem and why was it solved?
In your case moving to the more dangerous method appears to have stopped your crash. I can not explain why that is. But you may not have removed the problem, it may be that you have undefined behavior elsewhere that has simply stopped manifesting in this case but that may resurface later with a different change.