Magic Statics
Magic statics, more formally known as function-local static initialization, is when a static variable is declared within a function, and then passed to the caller.
It looks like:
The above code creates a new static qualified string inside the function, and then returns a reference to it. Seeing a reference being returned to a locally defined variable should give you the heebie jeebies! This is the only time I can think of where this kind of behaviour is allowed (if the variable was not declared static, then it would be deleted when the function returned, and accessing the reference would likely crash your system!).
Thread Safety
Since C++11, the initialization of magic statics is guaranteed to be thread safe. Internally, the first thread that calls GetString() will initialize the pointer, blocking until initialization is complete. All other threads will then use the initialized value. Before C++11, calling GetString() from multiple threads is classified as undefined behaviour (UB).
§6.7 [stmt.dcl] p4: If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.
Singletons
Magic statics allows for alternative implementation of the Singleton pattern.
The constructor and destructor is made private, and both the copy and move constructors deleted, so that this class cannot be duplicated/transferred in anyway.
This is sometimes called the Meyers’ Singleton after Scott Meyers publication “C++ and the Perils of Double-Checked Locking”.
Lazy Initialization
Magic statics allows for the concept of lazy initialization. This means that the object only gets created if it is used (e.g. in the example above, by calling GetInstance()
).
Hiding Global Statics
Magic statics can be used to hide otherwise globally defined static variables. In general, it is a bad idea to define global objects, and making the user call a function to retrieve the static instead resolves this issue.
Vendor Support
Most C++ compilers support magic statics, but you have to be careful about the thread safety aspect, as this was only introduced into the C++ standard in C++11! Any C++11 compliant version of GCC will support thread-safe magic statics.
On the Windows side of things, thread safety was implemented for magic statics in Visual Studio 2015.
Recursive Calls
Do NOT recursively call a function which allocates variables with static storage duration, as this behaviour is undefined.
§6.7 [stmt.dcl] p4: If control re-enters the declaration recursively while the variable is being initialized, the behavior is undefined.