static constructors in C++? I need to initialize private static objects

Viewed 181281

I want to have a class with a private static data member (a vector that contains all the characters a-z). In java or C#, I can just make a "static constructor" that will run before I make any instances of the class, and sets up the static data members of the class. It only gets run once (as the variables are read only and only need to be set once) and since it's a function of the class it can access its private members. I could add code in the constructor that checks to see if the vector is initialized, and initialize it if it's not, but that introduces many necessary checks and doesn't seem like the optimal solution to the problem.

The thought occurs to me that since the variables will be read only, they can just be public static const, so I can set them once outside the class, but once again, it seems sort of like an ugly hack.

Is it possible to have private static data members in a class if I don't want to initialize them in the instance constructor?

22 Answers

To get the equivalent of a static constructor, you need to write a separate ordinary class to hold the static data and then make a static instance of that ordinary class.

class StaticStuff
{
     std::vector<char> letters_;

public:
     StaticStuff()
     {
         for (char c = 'a'; c <= 'z'; c++)
             letters_.push_back(c);
     }

     // provide some way to get at letters_
};

class Elsewhere
{
    static StaticStuff staticStuff; // constructor runs once, single instance

};

Well you can have

class MyClass
{
    public:
        static vector<char> a;

        static class _init
        {
          public:
            _init() { for(char i='a'; i<='z'; i++) a.push_back(i); }
        } _initializer;
};

Don't forget (in the .cpp) this:

vector<char> MyClass::a;
MyClass::_init MyClass::_initializer;

The program will still link without the second line, but the initializer will not be executed.

In the .h file:

class MyClass {
private:
    static int myValue;
};

In the .cpp file:

#include "myclass.h"

int MyClass::myValue = 0;

Here is another approach similar to Daniel Earwicker's, also using Konrad Rudolph's friend class suggestion. Here we use an inner private friend utility class to initialize the static members of your main class. For example:

Header file:

class ToBeInitialized
{
    // Inner friend utility class to initialize whatever you need

    class Initializer
    {
    public:
        Initializer();
    };

    friend class Initializer;

    // Static member variables of ToBeInitialized class

    static const int numberOfFloats;
    static float *theFloats;

    // Static instance of Initializer
    //   When this is created, its constructor initializes
    //   the ToBeInitialized class' static variables

    static Initializer initializer;
};

Implementation file:

// Normal static scalar initializer
const int ToBeInitialized::numberOfFloats = 17;

// Constructor of Initializer class.
//    Here is where you can initialize any static members
//    of the enclosing ToBeInitialized class since this inner
//    class is a friend of it.

ToBeInitialized::Initializer::Initializer()
{
    ToBeInitialized::theFloats =
        (float *)malloc(ToBeInitialized::numberOfFloats * sizeof(float));

    for (int i = 0; i < ToBeInitialized::numberOfFloats; ++i)
        ToBeInitialized::theFloats[i] = calculateSomeFancyValue(i);
}

This approach has the advantage of completely hiding the Initializer class from the outside world, keeping everything contained within the class to be initialized.

No need for an init() function, std::vector can be created from a range:

// h file:
class MyClass {
    static std::vector<char> alphabet;
// ...
};

// cpp file:
#include <boost/range.hpp>
static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz";
std::vector<char> MyClass::alphabet( boost::begin( ::alphabet ), boost::end( ::alphabet ) );

Note, however, that statics of class type cause trouble in libraries, so they should be avoided there.

C++11 Update

As of C++11, you can do this instead:

// cpp file:
std::vector<char> MyClass::alphabet = { 'a', 'b', 'c', ..., 'z' };

It's semantically equivalent to the C++98 solution in the original answer, but you can't use a string literal on the right-hand-side, so it's not completely superior. However, if you have a vector of any other type than char, wchar_t, char16_t or char32_t (arrays of which can be written as string literals), the C++11 version will strictly remove boilerplate code without introducing other syntax, compared to the C++98 version.

The concept of static constructors was introduced in Java after they learned from the problems in C++. So we have no direct equivalent.

The best solution is to use POD types that can be initialised explicitly.
Or make your static members a specific type that has its own constructor that will initialize it correctly.

//header

class A
{
    // Make sure this is private so that nobody can missues the fact that
    // you are overriding std::vector. Just doing it here as a quicky example
    // don't take it as a recomendation for deriving from vector.
    class MyInitedVar: public std::vector<char>
    {
        public:
        MyInitedVar()
        {
           // Pre-Initialize the vector.
           for(char c = 'a';c <= 'z';++c)
           {
               push_back(c);
           }
        }
    };
    static int          count;
    static MyInitedVar  var1;

};


//source
int            A::count = 0;
A::MyInitedVar A::var1;

When trying to compile and use class Elsewhere (from Earwicker's answer) I get:

error LNK2001: unresolved external symbol "private: static class StaticStuff Elsewhere::staticStuff" (?staticStuff@Elsewhere@@0VStaticStuff@@A)

It seems is not possible to initialize static attributes of non-integer types without putting some code outside the class definition (CPP).

To make that compile you can use "a static method with a static local variable inside" instead. Something like this:

class Elsewhere
{
public:
    static StaticStuff& GetStaticStuff()
    {
        static StaticStuff staticStuff; // constructor runs once, single instance
        return staticStuff;
    }
};

And you may also pass arguments to the constructor or initialize it with specific values, it is very flexible, powerfull and easy to implement... the only thing is you have a static method containing a static variable, not a static attribute... syntaxis changes a bit, but still useful. Hope this is useful for someone,

Hugo González Castro.

Wow, I can't believe no one mentioned the most obvious answer, and one that most closely mimics C#'s static-constructor behavior, i.e. it doesn't get called until the first object of that type is created.

std::call_once() is available in C++11; if you can't use that, it can be done with a static boolean class-variable, and a compare-and-exchange atomic-operation. In your constructor, see if you can atomically change the class-static flag from false to true, and if so, you can run the static-construction code.

For extra credit, make it a 3-way flag instead of a boolean, i.e. not run, running, and done running. Then all other instances of that class can spin-lock until the instance running the static-constructor has finished (i.e. issue a memory-fence, then set the state to "done running"). Your spin-lock should execute the processor's "pause" instruction, double the wait each time up until a threshold, etc. — pretty standard spin-locking technique.

In the absence of C++11, this should get you started.

Here's some pseudocode to guide you. Put this in your class definition:

enum EStaticConstructor { kNotRun, kRunning, kDone };
static volatile EStaticConstructor sm_eClass = kNotRun;

And this in your constructor:

while (sm_eClass == kNotRun)
{
    if (atomic_compare_exchange_weak(&sm_eClass, kNotRun, kRunning))
    {
        /* Perform static initialization here. */

        atomic_thread_fence(memory_order_release);
        sm_eClass = kDone;
    }
}
while (sm_eClass != kDone)
    atomic_pause();

You define static member variables similarly to the way you define member methods.

foo.h

class Foo
{
public:
    void bar();
private:
    static int count;
};

foo.cpp

#include "foo.h"

void Foo::bar()
{
    // method definition
}

int Foo::count = 0;

To initialize a static variable, you just do so inside of a source file. For example:

//Foo.h
class Foo
{
 private:
  static int hello;
};


//Foo.cpp
int Foo::hello = 1;

How about creating a template to mimic the behavior of C#.

template<class T> class StaticConstructor
{
    bool m_StaticsInitialised = false;

public:
    typedef void (*StaticCallback)(void);

    StaticConstructor(StaticCallback callback)
    {
        if (m_StaticsInitialised)
            return;

        callback();

        m_StaticsInitialised = true;
    }
}

template<class T> bool StaticConstructor<T>::m_StaticsInitialised;

class Test : public StaticConstructor<Test>
{
    static std::vector<char> letters_;

    static void _Test()
    {
        for (char c = 'a'; c <= 'z'; c++)
            letters_.push_back(c);
    }

public:
    Test() : StaticConstructor<Test>(&_Test)
    {
        // non static stuff
    };
};

For simple cases like here a static variable wrapped inside a static member function is nearly as good. It's simple and will usually be optimized away by compilers. This does not solve initialization order problem for complex objects though.

#include <iostream>

class MyClass 
{

    static const char * const letters(void){
        static const char * const var = "abcdefghijklmnopqrstuvwxyz";
        return var;
    }

    public:
        void show(){
            std::cout << letters() << "\n";
        }
};


int main(){
    MyClass c;
    c.show();
}
Related