C++ PROGRAMMING

Magic Statics

Article by:
Date Published:
Last Modified:

Overview

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:

1
2
3
4
5
6
std::string& GetString() {
    // Create a local static variable
    static std::string magicStatic("Hello");
    // Return a reference to it! :-O
    return magicStatic;
}

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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Singleton final
{
public:
    static Singleton& GetInstance();
    
private:
    Singleton() = default;
    ~Singleton() = default;

    // Delete the copy and move constructors 
    Singleton(const CSingleton&) = delete;
    Singleton& operator=(const CSingleton&) = delete;
    Singleton(CSingleton&&) = delete;
    Singleton& operator=(CSingleton&&) = delete;
};
    
Singleton& Singleton::GetInstance()
{
    // Let's create a magic static
    static Singleton instance;
    return instance;
}

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 “<em>C++ and the Perils of Double-Checked Locking</em>”.

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.

Table showing Visual Studio's support for magic statics. Image from https://msdn.microsoft.com/en-us/library/hh567368.aspx.
Table showing Visual Studio's support for magic statics. Image from https://msdn.microsoft.com/en-us/library/hh567368.aspx.

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.


Authors

Geoffrey Hunter

Dude making stuff.

Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License .

Related Content:

Tags

comments powered by Disqus