3

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?

Deamonpog
  • 805
  • 1
  • 10
  • 24
  • So , where i start. Why is your MySelf ctor private?! if this hasn't any real reason, i would set it to public. Then you can avoid friend ;) I would create a ctor for your class GenericSingleton how should be private, that nobody could make an instance of it. And yes, your GenericSingleton Class looks well. – demonking Nov 29 '12 at 09:43
  • @demonking : No. all i want is to make the `MySelf` class a singleton. – Deamonpog Nov 29 '12 at 09:52
  • You may want a peek at [this question](http://stackoverflow.com/questions/1661529/is-meyers-implementation-of-singleton-pattern-thread-safe) concerning thread safety of Meyer's Singleton, while you're perusing the db. – WhozCraig Nov 29 '12 at 09:53
  • but I am using C++03 :P and its VC++ – Deamonpog Nov 29 '12 at 10:10
  • Note: [singleton is considered an anti-pattern](http://stackoverflow.com/a/138012/1968). Don’t use it. – Konrad Rudolph Nov 29 '12 at 13:52
  • @Konard Rudolph: yes i am now also considering about using a namespace with static functions and static variables. I will update the findings. – Deamonpog Nov 29 '12 at 13:55

2 Answers2

6

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.

Community
  • 1
  • 1
Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • but i am using an old compiler and thats why i didn't use the mayers version and that is the reason for creating another class as a friend and giving it a static varible instance of `MySelf`. :P i guess every attempt has a disadvantage :P hehe... – Deamonpog Nov 29 '12 at 10:09
  • Is 'Meyer's Singleton' guaranteed to be lock-free in c++11? If not then it's next to useless I'm afraid. –  Nov 29 '12 at 10:14
  • In c++11 the `static` inside function scope will also be initialized at the begining. rite? but if thats true, the *initialization order fiasco* will affect it rite? – Deamonpog Nov 29 '12 at 10:20
  • @Deamonpog No, it won't. It will be initialized the first time the function is entered, so you're guaranteed that the object is constructed properly once the function returns, which is the first time you can use the object from outer code, anyway. – Christian Rau Nov 29 '12 at 10:34
  • then, what can i do for thread safety issue of it ? ( im not using C++11 ) – Deamonpog Nov 29 '12 at 10:35
  • @Daemonpog: either instantiate all singletons before any threading (e.g. the very first thing in main) or just lock your `Instance` method every time (note: double checked locking [does not work](http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf)) – KillianDS Nov 29 '12 at 10:57
  • @KillianDS: ya thats what i was thinking. init in the main. i will edit the question to add some details then. – Deamonpog Nov 29 '12 at 13:33
  • @Deamonpog: in general a simple mutex can be a global variable (namespace scope) and there will be no initialization order issue because it will be initialized during the `static initialization` phase (during which no code is executed) prior to the `dynamic initialization` phase. – Matthieu M. Nov 29 '12 at 14:09
  • @Matthieu M.: I was trying to do it with mutexes in windows api ( in windows its a HANDLE ) but it doesn't seem to have a nice initializer such as `PTHREAD_MUTEX_INITIALIZER` in pthreads :P – Deamonpog Nov 30 '12 at 07:11
5

Here is simpler implementation:

template <class T>
class GenericSingleton
{
public:
    static T& GetInstance()
    {
        static T _instance;
        return _instance;
    }
};

It also thread safe in C++11, because static variable creates before any thread.

Denis Ermolin
  • 5,530
  • 6
  • 27
  • 44
  • How does this answer his question? – KillianDS Nov 29 '12 at 09:39
  • 3
    What's the point of returning a pointer ? Is there *any* chance that it might be null ? – Matthieu M. Nov 29 '12 at 09:41
  • @KillianDS: the justification is wrong actually but the premise is right. It is thread-safe starting in C++11, it was already thread-safe when compiling with gcc in C++03 (and I think guaranteed by the Itanium ABI actually). – Matthieu M. Nov 29 '12 at 09:50
  • I didnt want to do this because i read in several places that `static` inside a function scope is NOT thread safe. isn't it? – Deamonpog Nov 29 '12 at 09:54
  • it's not thread safe in C++03, in C++11 it's thread safe. And yes, better return reference – Denis Ermolin Nov 29 '12 at 09:55
  • @Deamonpog: it was not guaranteed to be thread-safe in C++03, but some compilers (such as gcc and probably clang/icc) were already providing that guarantee. I don't know about VC++ though. – Matthieu M. Nov 29 '12 at 09:58
  • 1
    @Deamonpog It’s not thread safe in C++03 simply because the C++03 standard doesn’t know about threads. In C++03, there is *no* pure C++ implementation which can be thread safe. – Konrad Rudolph Nov 29 '12 at 13:54