Emulating the static initialization blocks of Java in C++

What is a static initialization block?

In Java, there is a language construct called a static initialization block. The static initialization block will be called the first time the class is loaded by the Java runtime. For example, consider the following code snippet1:

This produces the output:

I'm the static initialization block of Foo
I'm the constructor of Foo
I'm the constructor of Foo

This construct can be useful in a variety of situations. In Java, the intended use case is to allow multiline initialization of static members of a class. It can also be used for logging and any kind of “registration” or “subscription” code (such as for script binding).

C++ lacks this construct, but with some clever use of the language it’s possible to mimic certain aspects of it.

What can be emulated?

First of all, there is no such thing as a runtime in C++, at least not in the Java sense. This implies that the above definition can’t be replicated exactly in C++. Thus, the goal is to have a construct which

  • Uses minimal boilerplate2
  • Is easy to understand (that is, the syntax is straightforward)
  • Acts inside the scope of the class, as a static function
  • Executes code at a deterministic point, preferably at the start of main

The syntax

From the above requirements (and some restrictions to be mentioned), the following is the intended syntax for the static initialization block:

In foo.h:


#pragma once
#include "static_init.h"

class Foo
{
public:
    Foo();
    DECLARE_STATIC_INIT(Foo);
};

In foo.cc:

#include <iostream>
#include "foo.h"

Foo::Foo()
{
    std::cout << "I'm the constructor of Foon";
}

STATIC_INIT(Foo)
{
    std::cout << "I'm the static initialization block of Foon";
}

In main.cc:

#include <iostream>
#include "static_init.h"
#include "foo.h"

int main()
{
    static_init::execute();
    Foo foo1, foo2;
}

This code is expected to produce the same output as the Java snippet above.

Implementation

So what goes into static_init.h? From the code in main, it’s not hard to guess that one part of the implementation is some sort of registry. This is true, and it looks like this:


typedef void (*init_func_type)();

class static_init
{
public:
    static static_init& instance()
    {
        static static_init inst;
        return inst;
    }

    void add_init_func(init_func_type f) { funcs_.push_back(f); }

    static void execute() 
    { 
        auto& inst = instance();
        for (auto& c : inst.funcs_) c(); 
    }

private:
    static_init() {}

    std::vector<init_func_type> funcs_;
};

static_init is a singleton that manages and executes void functions. init_func_type is a typedef for a function pointer that points to a function that takes no parameters. They will be used to point to static member functions, . std::function would also work here, but would be less efficient. The execute member function is static merely for syntactic niceness on the calling side, nothing else.

Where is add_init_func called? The trick is to call it in a constructor of a static member. This constructor takes the init function as a parameter and passes it to add_init_func. Theoretically, it would be possible to call that function right there (and eliminate the need for the “init function registry”), but doing so would make our code affected by the “static initialization order fiasco”. We don’t want to impose any restrictions on the clients of our library, so we are taking this approach.3.

For the static member where we sneak in the registration code, we need to define a helper class. This is rather simple:


class static_init_helper
{
public:
   static_init_helper(init_func_type f)
   {
       static_init::instance().add_init_func(f);
   }
};

At this point we have everything we need for the functionality. Foo.h would have code like:


#pragma once
#include "static_init.h"

class Foo
{
public:
    Foo();
    static void static_init_func();
    static static_init_helper Foo_static_init_helper;
};

And in foo.cc:

#include <iostream>
#include "foo.h"

Foo::Foo()
{
    std::cout << "I'm the constructor of Foon";
}

// This is where the registration code (i.e. the constructor of the helper class) gets called:
static_init_helper Foo::Foo_static_init_helper(&Foo::static_init_func);

// And this is the implementation of the static init function,
// an actual static member function of the class.
void Foo::static_init_func()
{
    std::cout << "I'm the static initialization block of Foon";
}

It works, but not pretty.

Making it pretty

I intentionally arranged the above code in a way that makes it easy to see what can be repeated by a macro. The declaration part is very straightforward:

#define DECLARE_STATIC_INIT(ClassName) 
   static void static_init_func(); 
   static static_init_helper ClassName##_static_init_helper

Note the lack of semi-colon at the end. This is merely a personal preference, it could be added. Personally I like if my macros look and feel like statements, and this helps with that.

Similarly, the implementation part:

#define STATIC_INIT(ClassName) 
   static_init_helper ClassName::ClassName##_static_init_helper(&ClassName::static_init_func); 
   void ClassName::static_init_func()

But, here you may not add a semi-colon at the end, since the macro ends with the signature of the member function that’s about to be written. This is what allows the macro to act like a part of a function definition.

Shortcomings

One problem was already mentioned above: while the static init functions are not directly affected by the “static initialization order fiasco” (i.e. they can expect static members of any class to be fully constructed), they may not depend on each other, because the order they will be called is not defined.

This solution introduces a somewhat alien concept into the land of C++4. That implies an increased overhead for programmers reading the code that uses it. Still, with the right naming the intention of this code should be easy to guess.

Also, this adds a data member to the class. While this data member is 0 sized, it still needs to exist in a source file to be linked correctly. This means that the static init function can’t be inline-only.5

Source code

The source code for this article (along with some example code) is available in the GitHub repository.


  1. The highlighting in this code snippet is different because highlight.js had problems with this rarely used construct. As a workaround, I used a GitHub Gist for displaying this snippet. 

  2. That is, the solution does not depend on the user calling a specific member function in each class for example, and has no dependency on each class that uses the construct 

  3. One restriction that still remains is that the order of static init functions is not specified, they will be called in the order the constructors of the static members ran, which is not defined in the standard 

  4. Although it’s far from some of the more advanced Boost libraries 

  5. Some compilers allow calling a function for static member initialization but that is not allowed by the standard. 

  • Anuj Kohli

    Hi Tamás Szelei
    Is

    for (auto& c : inst.funcs_) c(); line in the static_init.h file correctly written.

    It is showing error when I am trying to implement it that reference variable c requires an initializer .
    Can you please respond asap .

    thanks
    Anuj Kohli from India

    • Tamás Szelei

      Yes, the line is correct. Make sure you are compiling with a C++11 compliant compiler, such as gcc 4.8+, clang 3.2+. Visual Studio 2010 won’t work, you will get the error you wrote. (I must update the readme, because at the time I did not have access to VS2010 and wrongly assumed it supports at least this much from C++11). VS2013 can compile the file without problems, I just tried it.
      PS. Please refrain from asking for “asap” answers, I’m doing this blog in my free time, pro bono. Also, adding me on Facebook is really weird, I don’t know you. Please don’t do that.