31

What is the rationale for not having static constructor in C++?

If it were allowed, we would be initializing all the static members in it, at one place in a very organized way, as:

//illegal C++
class sample
{
public:

    static int some_integer;
    static std::vector<std::string> strings;

    //illegal constructor!
    static sample()
    {
       some_integer = 100;
       strings.push_back("stack");
       strings.push_back("overflow");
    }
};

In the absense of static constructor, it's very difficult to have static vector, and populate it with values, as shown above. static constructor elegantly solves this problem. We could initialize static members in a very organized way.

So why doesn't' C++ have static constructor? After all, other languages (for example, C#) has static constructor!

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 5
    Search for "static initialization order fiasco". – Hans Passant Mar 14 '11 at 16:52
  • @Matti: Of course, before the program enters into `main()`. – Nawaz Mar 14 '11 at 16:52
  • 1
    @Nawaz: In what order? And how would this tie into the object formats that come from before C++? – Matti Virkkunen Mar 14 '11 at 17:31
  • 1
    @Matti: You're talking about this ordering thingy as if it's obviously impossible to run the static constructor. – Nawaz Mar 14 '11 at 17:34
  • @Nawaz: If it's all obvious for you, why don't you try answering my two questions. – Matti Virkkunen Mar 14 '11 at 17:35
  • @Matti: It's obviously obvious, imagine the static constructor as function which must be called before entering into the `main()` : see this : http://stackoverflow.com/questions/4783404/is-main-really-start-of-a-c-program – Nawaz Mar 14 '11 at 17:38
  • 1
    @Matti: I'd say before the constructors of static objects (which in turn are executed before the `main`), in "implementation defined" order. I see nothing impossible in having static constructors in C++, my opinion is that they just forgot/didn't want to add extra complexity to compilers/supposed that `static` objects were enough for these purposes. – Matteo Italia Mar 14 '11 at 17:51
  • @Matteo: Your comment makes perfect sense. I liked the honesty in it. – Nawaz Mar 14 '11 at 17:55
  • 1
    @Nawaz: thank you. By the way, the "implementation defined" order is already in place for `static` objects initialization (see §3.6.2). – Matteo Italia Mar 14 '11 at 18:00
  • @Matteo: So what that has to do with it now? – Nawaz Mar 14 '11 at 18:04
  • @Nawaz: I was just pointing out that the problem of `static` constructors execution order has been already solved for constructors of `static` objects as I expected (actually it's not "implementation defined" but "unspecified"). – Matteo Italia Mar 14 '11 at 18:09

5 Answers5

23

Using the static initialization order problem as an excuse to not introducing this feature to the language is and always has been a matter of status quo - it wasn't introduced because it wasn't introduced and people keep thinking that initialization order was a reason not to introduce it, even if the order problem has a simple and very straightforward solution.

Initialization order, if people would have really wanted to tackle the problem, they would have had a very simple and straightforward solution:

//called before main()

int static_main() {

ClassFoo();
ClassBar();

}

with appropriate declarations:

class ClassFoo {
 static int y;
  ClassFoo() {
   y = 1;
  }
}

class ClassBar {
  static int x;
  ClassBar() {
   x = ClassFoo::y+1;
  }
}

So the answer is, there is no reason it isn't there, at least not a technical one.

Krizz
  • 11,362
  • 1
  • 30
  • 43
lurscher
  • 25,930
  • 29
  • 122
  • 185
  • How do you solve linking to a few libraries that also has a static_main? What's the order of static_main calls? – Erik Mar 14 '11 at 17:01
  • 2
    just like main; libraries should not have one – lurscher Mar 14 '11 at 17:04
  • 2
    +1 for saying this *"Using the static initialization order problem as an excuse to not introducing this feature to the language is and always has been a matter of status quo - it wasn't introduced because it wasn't introduced and people keep thinking that initialization order was a reason to not introduce it, even if the order problem has a simple and very straightforward problem"*. – Nawaz Mar 14 '11 at 17:04
  • This implies all the globals/statics have to be initialized in the same compilation unit? AFAIK, there's no problem with initializing them in only one compilation unit, as it is. You don't need a new syntax for this. – UncleBens Mar 14 '11 at 17:04
  • 1
    @lurscher: But then how do you control static initialization order in libraries? I agree that the static init order is a silly problem though. – Erik Mar 14 '11 at 17:06
  • 5
    most libraries require some initialization code in main() before they can be used; even if a library is used by other library, usually the only way to guarantee that initialisation happens just once is delegating such initialisation to the global main(). Having syntax for specifying static constructors doesn't magically solve that but makes the initialisation requirement explicit - you forgot to call your static ctor? hey the compiler will give a sane warning – lurscher Mar 14 '11 at 17:10
16

This doesn't really make sense for c++ - classes are not first class objects (like in e.g. java).

A (static|anything) constructor implies something is constructed - and c++ classes aren't constructed, they just are.

You can easily achieve the same effect though:

//.h
struct Foo {
  static std::vector<std::string> strings;
};
//.cpp
std::vector<std::string> Foo::strings(createStrings());

IMO there's just no need for one more syntactic way of doing this.

Erik
  • 88,732
  • 13
  • 198
  • 189
  • +1: It is not very different from the approach proposed by Nawaz. There is no need for static "constructors". – knivil Mar 14 '11 at 16:58
  • @knivil: just that it looks a bit unorganized. I mean, you write a function `createStrings()` elsewhere and you call it from here; makes things a bit difficult to understand and manage! – Nawaz Mar 14 '11 at 17:02
  • 4
    @Nawaz: C++ was never known for it's pretty and understandable syntax ;) – Erik Mar 14 '11 at 17:03
  • @Erik: :D.. people make things difficult and then think themselves as geeks :D – Nawaz Mar 14 '11 at 17:07
  • 5
    @Nawaz: I'd rather think they didn't know better at the time, or could not work out a way to make it backward compatible. – Matthieu M. Mar 14 '11 at 17:34
  • 1
    @Matthieu: Your comment makes sense to me. I appreciate the honesty in your comment. :D – Nawaz Mar 14 '11 at 17:36
6

In which translation unit would the static objects be placed?

Once you account for the fact that statics have to be placed in one (and only one) TU, it's then not "very difficult" to go the rest of the way, and assign values to them in a function:

// .h
class sample
{
public:
    static int some_integer;
    static std::vector<std::string> strings;
};

//.cpp

// we'd need this anyway
int sample::some_integer;
std::vector<std::string> sample::strings;

// add this for complex setup
struct sample_init {
    sample_init() {
       sample::some_integer = 100;
       sample::strings.push_back("stack");
       sample::strings.push_back("overflow");
    }
} x;

If you really want the code for sample_init to appear in the definition of class sample, then you could even put it there as a nested class. You just have to define the instance of it in the same place you define the statics (and after they've been initialized via their default constructors, otherwise of course you can't push_back anything).

C# was invented 15-20 years after C++ and has a completely different build model. It's not all that surprising that it offers different features, and that some things are less simple in C++ than in C#.

C++0x adds a features to make it easier to initialize vectors with some data, called "initializer lists"

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
5

You could get by with putting your "static" members in their own class with their own constructor that performs their initialization:

class StaticData
{
    int some_integer;
    std::vector<std::string> strings;

public:
    StaticData()
    {
       some_integer = 100;
       strings.push_back("stack");
       strings.push_back("overflow");
    }
}

class sample
{    
    static StaticData data;

public:
    sample()
    {

    }
};

Your static data member is guaranteed to be initialized before you first try to access it. (Probably before main but not necessarily)

Dave Rager
  • 8,002
  • 3
  • 33
  • 52
2

Static implies a function that is disassociated with an object. Since only objects are constructed, it is not apparent why a static constructor would have any benefit.

You can always hold an object in a static scope which has been constructed in a static block, but the constructor you would use would still be declared as non-static. There's no rule that indicates you can't call a non-static method from a static scope.

Finally, C++ / C defines the start of a program to be when the main function is entered. Static blocks are called prior to the entry of the main function as part of setting up the "environment" of the evaluated code. If your environment dictates full control over the set-up and tear-down, then it's easy to argue that it's not really some environmental fixture as much as an inherit procedural component of the program. I know that the last bit is sort of code-philosophy (and that it's rationale could be interpreted differently), but one shouldn't put critical code "before" the official start of an executable's handing off "full control" to the code written by the programmer.

Edwin Buck
  • 69,361
  • 7
  • 100
  • 138
  • 1
    What the OP is referring to is a "static initialization block". This is something that exists in Java, for example. It allows you to do precisely what the OP wants: initialize static field values. – Vojislav Stojkovic Mar 14 '11 at 16:54
  • I'm talking a feature that is not existing in C++ now. But you're explaining it's non-existence based on the current meaning of static. So your explanation doesn't seem rational. – Nawaz Mar 14 '11 at 16:55
  • @Nawaz, You're right, but I expanded my statement to include the C / C++ rationale for why such an item is still a bad idea. Certainly it is useful in some cases, but it pushes more code "before" the start of the program, which could be viewed as nonsense solution from a philosophical point of view, even if it has some practical benefits. It's one of those situations where the restrictions of C++ don't follow what you are trying to design, but a different way will do the job nicely. – Edwin Buck Mar 14 '11 at 16:59
  • @Nawaz, Thinking about about the implications of your comment. If new features don't follow the current defintions of C++, that's fine, but then again, the new resulting language can't be rightfully called C++ either. I don't think they can rationally add this without guaranteeing that a constructor is available in the static environment. Some improvement in the ordering of the way object files are loaded will be needed. Such an ordering means that you could force the evaluation of the static blocks into a certain order, which breaks most of how C++ sets up it's initial environment today. – Edwin Buck Mar 14 '11 at 17:23