javac++initializationequivalentstatic-block

What's the C++ idiom equivalent to the Java static block?


I have a class with some static members, and I want to run some code to initialize them (suppose this code cannot be converted into a simple expression). In Java, I would just do

class MyClass {
    static int field1;
    static int field2;

    static {
        /* do some computation which sets field1 and field2 */
    }
}

Unless I'm mistaken, C++ does not allow for such static code blocks, right? What should I be doing instead?

I would like solution for both of the following options:

  1. Initialization happens when process loads (or when the DLL with this class is loaded).
  2. Initialization happens when the class is first instantiated.

For the second option, I was thinking of:

class StaticInitialized {
    static bool staticsInitialized = false;

    virtual void initializeStatics();

    StaticInitialized() {
        if (!staticsInitialized) {
            initializeStatics();
            staticsInitialized = true;
        }
    }
};

class MyClass : private StaticInitialized {
    static int field1;
    static int field2;

    void initializeStatics() {
        /* computation which sets field1, field2 */
    }
};

but that's not possible, since C++ (at the moment?) does not allow initialization of non-const static members. But, at least that reduces the problem of a static block to that of static initialization by expression...


Solution

  • You can have static blocks in C++ as well - outside classes.

    It turns out we can implement a Java-style static block, albeit outside of a class rather than inside it, i.e. at translation unit scope. The implementation is a bit ugly under the hood, but when used it's quite elegant!

    Downloadable version

    There's now a GitHub repo for the solution, containing a single header file: static_block.hpp.

    Usage

    If you write:

    static_block {
        std::cout << "Hello static block world!\n";
    }
    

    this code will run before your main(). And you can initialize static variables or do whatever else you like. So you can place such a block in your class' .cpp implementation file.

    Notes:

    Implementation

    The static block implementation involves a dummy variable initialized statically with a function. Your static block is actually the body of that function. To ensure we don't collide with some other dummy variable (e.g. from another static block - or anywhere else), we need a bit of macro machinery.

    #define CONCATENATE(s1, s2) s1##s2
    #define EXPAND_THEN_CONCATENATE(s1, s2) CONCATENATE(s1, s2)
    #ifdef __COUNTER__
    #define UNIQUE_IDENTIFIER(prefix) EXPAND_THEN_CONCATENATE(prefix, __COUNTER__)
    #else
    #define UNIQUE_IDENTIFIER(prefix) EXPAND_THEN_CONCATENATE(prefix, __LINE__)
    #endif // __COUNTER__
    #ifdef _MSC_VER
    #define _UNUSED
    #else
    #define _UNUSED __attribute((unused))
    #endif // _MSC_VER
    

    and here is the macro work to put things together:

    #define static_block STATIC_BLOCK_IMPL1(UNIQUE_IDENTIFIER(_static_block_))
    
    #define STATIC_BLOCK_IMPL1(prefix) \
        STATIC_BLOCK_IMPL2(CONCATENATE(prefix,_fn),CONCATENATE(prefix,_var))
    
    #define STATIC_BLOCK_IMPL2(function_name,var_name) \
    static void function_name(); \
    static int var_name _UNUSED = (function_name(), 0) ; \
    static void function_name()
    

    Notes:

    Live Demo