3

I know the following is a thread-safe way to implement a singleton in C++11:

Foo* getInst()
{
    static Foo* inst = new Foo(...);
    return inst;
}

I read in this answer that the following is also thread-safe:

Foo& getInst()
{
    static Foo inst(...);
    return inst;
}

Is it really thread-safe?
Isn't it a problem that the instance of Foo will be allocated in a single stack frame will not be allocated on the heap?

If it is thread-safe, is there a strong reason to prefer one to the other?

Community
  • 1
  • 1
Kaveh
  • 426
  • 1
  • 6
  • 20
  • *Both* variables are static, implying the same lifetime semantics, so if the second one wasn't safe then the first one wouldn't be either. – cdhowie Nov 16 '14 at 08:22
  • 2
    Keep in mind that static initialization is thread-safe in c++11, previous versions of the standard do not make this guarantee. Additionaly, in MSVC2012 and 2013 the static initialization contains bugs and is actually not thread safe. For cross-platform code i would advice to avoid the usage of the so called magic statics. – Stefan Nov 16 '14 at 09:41

2 Answers2

9

Static variables are NOT allocated on the stack. In the first variant you have a static pointer (a global variable) initialized with a memory obtained from the heap, while in the second one you have whole static object.

Both versions use internal compiler guards (namely __cxa_guard_acquire() and __cxa_guard_release(), which are functionally equivalent to mutex::lock() and mutex::unlock()) to ensure serialized access to a special variable that tells whether or not your global instances are already initialized or not.

Your code:

Foo& getInst()
{
    static Foo inst(...);
    return inst;
}

will actually look like that after the compilation:

Foo& getInst()
{
    static Foo inst; // uninitialized - zero
    static guard instGuard; // zero

    if (is_initialized(instGuard) == false)
    {
        __cxa_guard_acquire(instGuard);
        // do the initialization here - calls Foo constructor
        set_initialized(instGuard);
        __cxa_guard_release(instGuard);
    }

    return inst;
}

So both of your exampes are thread safe.

Freddie Chopin
  • 7,520
  • 2
  • 23
  • 49
  • @Kaveh - exactly as safe as your first version. I'll edit the answer in a second to be more precise. – Freddie Chopin Nov 16 '14 at 08:14
  • I checked the standard. Static members work as you wrote by default (as long as they are not declared `thread_local` there will be a single instance for all threads). – Kaveh Nov 16 '14 at 08:44
4

inst in your example won't be allocated on stack. It will be allocated somewhere in .data or .bss section. Otherwise this static variable couldn't live all the time program executes, and so it couldn't have the same value, which was before, each time you enter this function.

justanothercoder
  • 1,540
  • 1
  • 11
  • 26