Thread-Unsafe Lazy Init (Pre-C++11)

When creating a Singleton causes undefined behavior in older C++.

The idea

A common way to create a Singleton (a class with only one instance) in C++ is to declare a static local variable inside a function. Because it's static, it is only initialized the first time the function is called (Lazy Initialization). But before C++11, if two threads called the function at the exact same time, the compiler did not guarantee thread safety. Thread B might see a half-constructed object!

Step 1: Two threads call get_instance() simultaneously in C++03.

How it works (Meyers Singleton)

In C++11 and later, the standard explicitly mandates that the initialization of block-scope static variables is thread-safe. The compiler automatically inserts hidden locking and Double-Checked Locking logic for you. This safe pattern is known as the Meyers Singleton.

// The Meyers Singleton

class Database {
public:
    static Database& get_instance() {
        // In C++11 and later, this is 100% thread-safe.
        // The compiler secretly adds locks around this initialization.
        static Database instance; 
        
        return instance;
    }
private:
    Database() {} // Private constructor
};

Cost

The cost in modern C++ is extremely low. The compiler optimizes the hidden locks so that after the first initialization, subsequent calls are lock-free and branch-predicted. It is the gold standard for Singletons in C++.

Watch out for