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

6

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!

Lemberg answered 14/3, 2011 at 16:49 Comment(11)
Search for "static initialization order fiasco".Ionium
@Matti: Of course, before the program enters into main().Lemberg
@Nawaz: In what order? And how would this tie into the object formats that come from before C++?Chemisorption
@Matti: You're talking about this ordering thingy as if it's obviously impossible to run the static constructor.Lemberg
@Nawaz: If it's all obvious for you, why don't you try answering my two questions.Chemisorption
@Matti: It's obviously obvious, imagine the static constructor as function which must be called before entering into the main() : see this : #4783904Lemberg
@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.Rencontre
@Matteo: Your comment makes perfect sense. I liked the honesty in it.Lemberg
@Nawaz: thank you. By the way, the "implementation defined" order is already in place for static objects initialization (see §3.6.2).Rencontre
@Matteo: So what that has to do with it now?Lemberg
@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").Rencontre
L
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.

Loosing answered 14/3, 2011 at 16:59 Comment(6)
How do you solve linking to a few libraries that also has a static_main? What's the order of static_main calls?Papaverine
just like main; libraries should not have oneLoosing
+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".Lemberg
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.Pl
@lurscher: But then how do you control static initialization order in libraries? I agree that the static init order is a silly problem though.Papaverine
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 warningLoosing
P
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.

Papaverine answered 14/3, 2011 at 16:54 Comment(6)
+1: It is not very different from the approach proposed by Nawaz. There is no need for static "constructors".Airbrush
@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!Lemberg
@Nawaz: C++ was never known for it's pretty and understandable syntax ;)Papaverine
@Erik: :D.. people make things difficult and then think themselves as geeks :DLemberg
@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.Classieclassification
@Matthieu: Your comment makes sense to me. I appreciate the honesty in your comment. :DLemberg
A
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"

Alleris answered 14/3, 2011 at 17:3 Comment(0)
D
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)

Dad answered 14/3, 2011 at 17:3 Comment(0)
N
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.

Nematic answered 14/3, 2011 at 16:51 Comment(4)
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.Kadi
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.Lemberg
@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.Nematic
@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.Nematic
A
1

Aside from other answers I think this feature is needed. Static constructor must get called before we use the static members or create an object i.e. before using the class.

What we are doing is writing a static function for initializing static members and calling that function. So. I think it would be nicer to have static constructors.

How to initialize static members of a class?.

Amphiaster answered 15/10, 2023 at 17:29 Comment(3)
The question is "Why is there no static constructor?", not "Why should there be?".Acquiescent
@Acquiescent I think that's how there shall be.Amphiaster
The idea for StackOverflow is that when you write an answer, you should actually answer the question. This is not a discussion forum, but a Q&A site. You might also consider that the other answers are from 2011, so you are quite a bit late here.Acquiescent

© 2022 - 2024 — McMap. All rights reserved.