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

178,330

Solution 1

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

};

Solution 2

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.

Solution 3

C++11 update

Since C++11, you can simply use lambda expressions to initialize static class members. You don't need to use any helper classes or workarounds anymore.

Header file:

class MyClass {
    static const vector<char> letters;
};

Source file:

// Initialize MyClass::letters with all letters from 'a' to 'z'.
const vector<char> MyClass::letters = [] {
    vector<char> letters;
    for (char c = 'a'; c <= 'z'; c++)
        letters.push_back(c);
    return letters;
}();

Note about static initialization order:

This approach also works if multiple static class members must be initialized in some specific order. Since static members are always initialized in the exact same order as defined within the source file, you just simply have to make sure that you write your initializations within the source file in the correct order.

Solution 4

In the .h file:

class MyClass {
private:
    static int myValue;
};

In the .cpp file:

#include "myclass.h"

int MyClass::myValue = 0;

Solution 5

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.

Share:
178,330

Related videos on Youtube

Gordon Gustafson
Author by

Gordon Gustafson

ML Platform Engineer at Motional. Experience in devops, backend development, and ML.

Updated on March 21, 2022

Comments

  • Gordon Gustafson
    Gordon Gustafson over 2 years

    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?

  • quark
    quark almost 15 years
    This works fine for individual static members (regardless of type). The deficiency in comparison to static constructors is that you can't impose an order between the various static members. If you need to do that, see Earwicker's answer.
  • Gordon Gustafson
    Gordon Gustafson almost 15 years
    thanks! though that's very annoying to have to do all that. One of the many "mistakes" C# and java learned from.
  • quark
    quark almost 15 years
    Yes. I always point out to people that if C++ hadn't made all those "mistakes" then other languages would have to make them. C++ covering so much ground, even making mistakes, has been great for the languages that followed it.
  • Oleg Zhylin
    Oleg Zhylin almost 15 years
    Just one little nuance, as constructors come into play no one guarantees when the constructor for static object executes. A well-known much safer approach is class Elsewhere { StaticStuff& get_staticStuff() { static StaticStuff staticStuff; // constructor runs once, when someone first needs it return staticStuff; } }; I wonder if static constructors in C# and Java can provide the same guarantee as the code above...
  • Martin York
    Martin York almost 15 years
    @Oleg: Yes they do. The standard gurantees that the constructors for all non local variables are executed before main is entered. It also gurantees that within a compilation unit the order of construction is well defined and the same order as declaration within the compilation unit. Unfortunately they do not define the order across multiple compilation units.
  • Daniel Earwicker
    Daniel Earwicker almost 15 years
    @Oleg: further to Martin's answer about order of construction in C++, the answer for C# is that code is dynamically loaded on demand, and statics are initialized on demand, and this is a thread-safe facility, so statics effectively work like thread-safe lazy singletons (with a built-in correct implementation of double-checked locking). Hence order-of-init problems can still occur where there are circular references, but they are unusual. Not sure how much this is true in Java.
  • Daniel Earwicker
    Daniel Earwicker almost 15 years
    As for language wars, it shouldn't be a surprise that Java has some nice things that C++ doesn't, as they were created a decade apart, and then C# came about five years after Java. This is surely not controversial. Also C++ and the other two languages don't even serve the same purpose, really.
  • Martin York
    Martin York almost 15 years
    I like it. Though if only we could do it in one line without the now usless alphabet.
  • Konrad Rudolph
    Konrad Rudolph over 14 years
    This is actually a case where friend makes a lot of sense so that class Elsewhere may easily access StaticStuff’s internals (without breaking encapsulation in any dangerous way, I might add).
  • ur.
    ur. over 14 years
    +1 (didn't try it out) But: When is ctor _init._init() called? Before or after the ctor of MyClass when I have a static MyClass object? I guess you can't tell...
  • Karel Bílek
    Karel Bílek about 14 years
    hello, where can I find more about this "initializer" magic?
  • Neel Basu
    Neel Basu about 13 years
    Shouldn't it be MyClass::a.push_back(i) instead of a.push_back(i) ?
  • Daniel Earwicker
    Daniel Earwicker over 12 years
    Though be careful if using threads. I believe in GCC the construction of static locals is protected against concurrent execution, but in Visual C++ it is not.
  • Ankit Roy
    Ankit Roy over 12 years
    @ur.: _initializer is a subobject of MyClass. Subobjects are initialised in this order: virtual base class subobjects, in depth-first, left-to-right order (but only initialising each distinct subobject once); then plain base class subobjects, in depth-first, left-to-right order; then member subobjects in order of declaration. So it's safe to use EFraim's strategy, provided that code in _initialiser only refers to members declared before it.
  • Blaisorblade
    Blaisorblade over 12 years
    FYI: I added the needed static definitions, plus made _init() private, and tested that the code still works.
  • drifter
    drifter about 12 years
    @Loki: Can you please specify which language standard you are referring to. It's not clear which of his arguments you're refuting.
  • Martin York
    Martin York about 12 years
    @drifter: My comment above is pointed at 'Oleg' comments (hence the @ Oleg). On the points I outlined above it has been like this since the earliest version of the standard I have read. But since the post was made in 2009 Lets go with N2960 but now you should be reading the latest: stackoverflow.com/a/4653479/14065
  • drifter
    drifter about 12 years
    @Loki: Oleg made two statements you could have been responding to: "...no one guarantees when the constructor for static object executes," and "I wonder if static constructors in C# and Java can provide the same guarantee..." Thank you for pointing out that the C++ standard does indeed guarantee this.
  • Jim Hunziker
    Jim Hunziker almost 12 years
    Though you might want to name I and i something a little more obscure so you don't accidentally use them somewhere lower in the file.
  • Jim Hunziker
    Jim Hunziker almost 12 years
    To be honest, it's hard to see why anyone would want to use private static members rather than anonmymous namespaces in implementation files.
  • OregonGhost
    OregonGhost over 11 years
    Tried at and it wouldn't work without declaring the _init constructor as public (or declaring _init as struct) on Visual C++ 2010. Should your code work as such?
  • EFraim
    EFraim over 11 years
    @Blaisorblade: Well I've verified with Studio 11 and it does not work with private static constructor (does not compile) - modifying the code to compile with standard C++.
  • Boris Dalstein
    Boris Dalstein over 10 years
    Wow, this is awesome! I wonder, why not make StaticStuff *inheriting*std::vector<char> instead of using composition? This would save a lot of typing later, and makes a lot of sense since you actually wanted your "static stuff" to be a vector of char, and just use this as a workaround for a limitation of C++. Any good reason for using composition in this case?
  • Daniel Earwicker
    Daniel Earwicker over 10 years
    Inheriting a type that is not designed to be inherited from is potentially problematic in C++, because such types don't have a virtual destructor. So std::vector<char> *p = new StaticStuff would be possible according to the type system, but delete p would caused Undefined Behaviour. If std::vector had a protected destructor, delete p would be blocked by the type system, but then we'd be forced to use std::vector only as a base class. If std::vector had a virtual destructor, it would be a tad more costly at runtime (which is antithetical to the C++ approach).
  • Daniel Earwicker
    Daniel Earwicker over 10 years
    IFF you only use StaticStuff as above (i.e. not polymorphically referenced) then it is technically okay to inherit std::vector, but in reality you probably don't want to expose all the public features of std::vector. You almost certainly want only the const features, so the shared vector doesn't get modified accidentally. And you may be able to cut the required interface down further even than that (always a good idea for interfaces to be minimal), which is most clearly done via composition.
  • jww
    jww over 10 years
    CrazyJugglerDrummer question was not about a static plain old data type :)
  • jww
    jww over 10 years
    CrazyJugglerDrummer question was not about a static plain old data type :)
  • Andrew Larsson
    Andrew Larsson over 10 years
    Also, you have to make sure that ToBeInitialized::Initializer::Initializer() gets called, so you need to add ToBeInitialized::Initializer ToBeInitialized::initializer; to the implementation file. I took some things from your idea and from EFraim's idea, and it works exactly as I need it to and looks clean. Thanks, man.
  • Zachary Kraus
    Zachary Kraus over 9 years
    For causing problems with libraries, does it matter if the static class is private or public? Additionally, does it matter if the library is static(.a) or dynamic(.so)?
  • Marc Mutz - mmutz
    Marc Mutz - mmutz over 9 years
    @ZacharyKraus: what's a public/private class? And no, while the problems are different, but overlapping, it doesn't matter whether the library is linked statically or dynamically.
  • Zachary Kraus
    Zachary Kraus over 9 years
    @MarcMutz-mmutz Sorry about using public/private class which is not correct C++ terminology. What I was referring to is the solution by EFraim above. In my version though, I made the static class member private. I was trying to understand if having a static class member as public or private makes a difference in library development and usability. My gut tells me it should not effect the library because users will never have access to either the static class member or the object its building, but I would love to get some guru's wisdom on this topic.
  • Marc Mutz - mmutz
    Marc Mutz - mmutz over 9 years
    @ZacharyKraus: The main problem with statics that require dynamic initialisation ([basic.start.init]/2) is that they run code. In libraries, it could be that the library code has already been unloaded when the destructors are run. If you want to hear more, I suggest to post a question about it.
  • Zachary Kraus
    Zachary Kraus over 9 years
    Thanks Ill post a question on this since I am using a descent amount of singletons in a dynamic library and some other static structures as well.
  • Marc Mutz - mmutz
    Marc Mutz - mmutz over 9 years
    From C++11 onwards, and in POSIX, it has to be thread-safe.
  • Flotolk
    Flotolk over 8 years
    I'm doing exactly that, but it still doesn't compile. And it says this is the problem area (in the constructor, not the header)
  • FlintZA
    FlintZA over 8 years
    I quite liked two other solutions above (this and this), but yours is the only one that ensures initialization of statics in the order they're needed across libraries. I just have a private static Instance method like yours above, and wrap access to other values in public static accessors that use that Instance method instead of direct references. Thanks.
  • Eric
    Eric over 7 years
    Why are you newing a char array only to immediately leak the pointer and overwrite it!?
  • rafi wiener
    rafi wiener over 6 years
    interesting solution. in this case if i throw an exception who can catch it?
  • emkey08
    emkey08 over 6 years
    Static program initialization code must never throw any exceptions, or the program will crash. You must wrap the initializer logic into a try catch block if exceptions might be thrown.