2

Bring you two different implantation of singleton design pattern:

static class member

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; 
};

static member variable

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

Questions

  1. Can we consider both impl. as a valid impl. of the design pattern?
  2. Are both, functionally, the same?

Motivation

Background

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.

Problem

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.

Solution

I've changed SingletonFSV impl. to SingletonCSM and the crash stopped. make_shared returned a valid pointer and the problem was solved.

Question

I just don't understand what was the problem and why was it solved?

idanshmu
  • 5,061
  • 6
  • 46
  • 92
  • You should not inline `static SingletonFSVSp GetInstance()` –  Sep 21 '16 at 12:44
  • Do note that neither of these are singletons. They both have public constructors meaning you can make as many instances as you want. – NathanOliver Sep 21 '16 at 12:47
  • @DieterLücking is that related to the problem or just a general comment? 10x. – idanshmu Sep 21 '16 at 12:47
  • @NathanOliver correct I'll update the question – idanshmu Sep 21 '16 at 12:48
  • @idanshmu ... the static variable of that inline function (not put into a specific translation unit) is the problem. –  Sep 21 '16 at 13:05
  • GetInstance() should return SingletonCSMSp& and std::unique_ptr seems more appropriate than std::shared_ptr in your program. Otherwise SingletonFSV seems better because member variable spInstance in SingletonCSM is redundant as you can always use SingletonFSV ::GetInstance() to access the singleton. – seccpur Sep 23 '16 at 04:49

1 Answers1

2

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:

  1. Can we consider both impl. as a valid impl. of the design pattern?
  2. 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.

Galik
  • 47,303
  • 4
  • 80
  • 117
  • OK. but how does it explain the problem? I would expect `SingletonFSV` to work always while `SingletonCSM` may crash occasionally. but the problem is the other way around – idanshmu Sep 21 '16 at 12:53
  • @idanshmu Yes I can't answer your third question. I misread your problem and assumed the function static method solved it. This sounds like a job for your debugger because, in principle, using a static member is problematic and to be avoided whereas using a function static is considered the safe option. – Galik Sep 21 '16 at 12:58