219

I know this is an often asked question, but as there are so many variants, I'd like to re-state it, and hopefully have an answer reflecting the current state. Something like

Logger& g_logger() {
    static Logger lg;
    return lg;
}

Is the constructor of variable lg guaranteed to run only once?

I know from previous answers that in C++03, this is not; in C++0x draft, this is enforced. But I'd like a clearer answer to

  1. In C++11 standard (not draft), is the thread-safe initialization behavior finalized?
  2. If the above is yes, in current latest releases of popular compilers, namely gcc 4.7, vc 2011 and clang 3.0, are they properly implemented?
Nate
  • 11,467
  • 5
  • 42
  • 59
Ralph Zhang
  • 4,617
  • 4
  • 25
  • 36
  • 1
    Can I ask the purpose of such a function? What advantages does it have over a simple global `Logger g_logger;` – Chris Lutz Nov 12 '11 at 03:28
  • 17
    @Chris: Deterministic initialization and avoidance of the static initialization order fiasco. Local statics will first be initialized when the function is called the first time. – Xeo Nov 12 '11 at 04:37
  • 3
    Thanks Xeo, that's the main reason. Some others include: 1. Normally in a logging system, client code use it as macro, like LOG << "your log" ..., and the macros have to have an deterministic access to the logger 2. The logger is not created if you don't use it. 3. You probably don't want your client to create multiple loggers (there are synchronization issue, etc...) so the Logger has a private constructor, which is only accessible by friend g_logger() – Ralph Zhang Nov 12 '11 at 05:24
  • For the second question, No compilers have implemented this yet. – balki Dec 23 '12 at 21:29
  • 7
    @balki, GCC has implemented it for nearly a decade. Clang supports it too. – Jonathan Wakely Jan 15 '13 at 11:11
  • 2
    Visual Studio 2012 Update 3 does not support it - I tested it with a short test program and looked at the assembly code. – Tobias Langner Jul 02 '13 at 06:38
  • 12
    Nor, does it appear, will Visual Studio 2013. See the row "Magic statics" at http://msdn.microsoft.com/en-us/library/vstudio/hh567368(v=vs.120).aspx – rkjnsn Sep 15 '13 at 22:47
  • 1
    Is it safe in VS2013 if we ensure g_logger is called once from main() before any other threads are running? – paulm Nov 06 '14 at 15:21
  • 7
    "Magic statics" are finally coming with VS 2015: http://blogs.msdn.com/b/vcblog/archive/2014/11/17/c-11-14-17-features-in-vs-2015-preview.aspx – mlvljr Nov 21 '14 at 03:31

2 Answers2

198

The relevant section 6.7:

such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. [...] If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.

Then there's a footnote:

The implementation must not introduce any deadlock around execution of the initializer.

So yes, you're safe.

(This says nothing of course about the subsequent access to the variable through the reference.)

Kerrek SB
  • 428,875
  • 83
  • 813
  • 1,025
  • http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm –  Sep 29 '12 at 03:59
  • 29
    It is important to note that `static Logger lg;` is thread-safe only if the default constructor of `Logger` is thread-safe, i.e it doesn't accesses any modifiable shared resource internally, say through global variables or singletons. It should be noted that the Standard guarantees *only* this : if more one thread attempts to start executing the constructor concurrently, only one of them will *actually* execute it, the rest will wait for the completion of initialization. The Standard, however, doesn't give any guarantee of the thread-safety of the constructor itself. – Nawaz Jul 24 '14 at 12:41
  • Also, it says nothing about readers of the variable, which means you can have TSAN issues if you have any readers not preceded by the static constructor. Of course, if you use the pattern above (foo& GetFooLog() { static foo bar; return bar; } then the TSAN issue doesn't arise. – jesup Oct 02 '14 at 05:51
  • 11
    @Nawaz: WHy does the constructor have to be thread-safe? You said yourself that only one thread will execute the constructor. – Kerrek SB Oct 02 '14 at 09:47
  • 7
    @KerrekSB: I've also explained what I meant by that : *i.e it doesn't accesses any **modifiable shared resource** internally*. Just because only one thread executes a constructor, doesn't necessarily mean that what it does is thread-safe. If it modifies unprotected shared resource, then it wouldn't be threadsafe. – Nawaz Oct 02 '14 at 10:10
  • 47
    @Nawaz: Well, that's true, but that's also a complete generality: Concurrent access of shared data must be synchronized. I don't think that there's any suggestion that static initialization would somehow provide an exemption from that rule, so I didn't think it worth calling out specifically. – Kerrek SB Oct 02 '14 at 10:44
  • Seems a bit of a shame that neither this question nor answer mention the phrase "Meyers Singleton" – Nemo Jun 11 '17 at 05:33
  • 3
    Will this be valid for `static Logger *lg = new Logger();` as well? – user3819404 Apr 16 '19 at 14:24
  • @user3819404: At block scope, yes. (But then the object would never be deleted. Which may be desirable.) – Kerrek SB Apr 16 '19 at 23:04
  • Following on to @user3819404's question, I think this answers it: https://godbolt.org/z/3j5oxM I believe that "... control enters the declaration concurrently ..." considers the "declaration" to be the entire expression, so that logger example is not the same as `auto tmp = new Logger(); static Logger* lg = tmp;`: The RHS is called once, not just the c'tor of the LHS. For the logger example, `static Logger lg;` would suffice and would be cleaned up at the end of the program. – Ben Sep 04 '20 at 15:47
20

--fno-threadsafe-statics also worth mentioning. In gcc:

Do not emit the extra code to use the routines specified in the C++ ABI for thread-safe initialization of local statics. You can use this option to reduce code size slightly in code that doesn't need to be thread-safe.

Also, have a look at the old thread Are function static variables thread-safe in GCC?

Community
  • 1
  • 1
Denis Glotov
  • 198
  • 2
  • 5