Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Singleton implementation using friend class (C++)

I came up with this while trying to create a singleton. Example: ( I am trying to make MySelf a singleton which is thread safe and without using double checked locking )

class MySelf
{
private:
    string Name;
    int Age;

    MySelf()
    {
        Name = "Deamonpog";
        Age = 24;
        cout << "Constructing MySelf : " << Name << endl;
    };

    friend class MySingleton;

public:
    ~MySelf(){ cout << "Destructing MySelf : " << Name << endl; };

    int MyAge() const
    {
        return Age;
    }
};

class MySingleton
{
private:
    static MySelf mself;
public:
    static MySelf * GetInstance()
    {
        return &mself;
    }
};

MySelf MySingleton::mself;

Now i can easily use it like,

cout << "I am " << MySingleton::GetInstance()->MyAge() << endl;

I dont want lazy initialization because the class i am gonna create is going to be there from the start to end. But is this thread safe? ( to my knowledge it seems ok )

If this is ok, then shall i use generic programming like this,

template <class T>
class GenericSingleton
{
private:
    static T _instance;

public:
    static T * GetInstance()
    {
        return &_instance;
    }
};

template <class T>
T GenericSingleton<T>::_instance;

So i can use this with any other class too. and i just have to add friend class GenericSingleton<MySelf>; to the needed sigleton ( e.g. to MySelf class ).

Could this implementation cause trouble? I am actually creating a library. Some singletons are to be exported and some are not. Also what if this is for not a library but just another application?

-- EDIT --

So now i have to do it like this (since i am using VC++ which still doesn't support C++11 ) ,

static MySelf & GetInstance()
{
    WaitForMutex(mymutex); // some function from the threading library
    if( NULL == _instance )
    {
         _instance = new MySelf();
    }
    ReleaseMutex(mymutex); // release function of the same library
    Return _instance;
}

And tell the user to use the function once and cache it for usage after that. ( Or i can also rename the function to Initialize() and make another method for just returning the reference without any lock or creation. ) So where does the mymutex should be? and where should it be initialized?

like image 242
Deamonpog Avatar asked Apr 10 '26 04:04

Deamonpog


1 Answers

No, but it's not the primary issue.

The initialization of global objects (such as static) is unordered across translation units; meaning that if during the creation of one global I was calling MySingleton::GetInstance() I could end up with a pointer to unitialized memory.

See Initialization Order Fiasco.

On top of that, if I were to have a second thread starting up during this phase of initialization, it could access to a partially initialized object.

In general, the recommendation is to use Meyer's Singleton:

MySelf& MySelf::Instance() { static MySelf S; return S; }

which sidesteps the initialization order fiasco in two ways:

  • it is guaranteed that the object be initialized when Instance() returns
  • from C++11 onwards, compilers are required to instrument the initialization code such that a re-entrant access during initialization is detected (gcc already did in C++03)

furthermore, from C++11 onwwards, this is required to be thread-safe: that is, shall another thread call Instance() while the object is being constructed it will wait patiently until the end of the construction and then return the same instance as all other threads (gcc already did in C++03).

Note: using an extraneous class is just more typing for no added value, ditch it.

like image 123
Matthieu M. Avatar answered Apr 12 '26 21:04

Matthieu M.