3

I know we can have default value for struct members. For instance, I can set default value for those members:

struct Foo {
  int a = 0;
  int b = 1;
  int c;
}

Suppose I have another constructor for member c:

struct Foo {
  int a = 0;
  int b = 1;
  int c;
  foo(int input_c): c(input_c) {}
}

In this case, when I construct a Foo, what's the order of construction? If I do

Foo(100)

My understanding is both a and b are default constructed first then c is assigned 100, is it correct?

------------- Updates ---------------------

Part of my confusion is also the order of execution. For the default values, is it already executed before the constructors?

For instance, I can change my Foo

struct Foo {
  int a = 0;
  int b = 1;
  int c = -1;
  foo(int d) {
    c += d;     // Does c always started with -1?
  }
}
Jesper Juhl
  • 30,449
  • 3
  • 47
  • 70
WhatABeautifulWorld
  • 3,198
  • 3
  • 22
  • 30

2 Answers2

4

The order initialization happens in is quite rigid, it is always the order the members are declared in.

First of all, all default in-class initializers are applied (in the order that members are declared) unless overruled by the initialization list.

Then the constructors initialization list is used and any members listed there are initialized in the order they are declared. If any of those listed members also have in-class initializers, then those don't happen and the initialization list wins and is used to initialize the members.

Then the constructor body is executed. At this point all members are already initialized, either by in-class initialization or the initializer list. But the constructor body can choose to assign new values to those initialized members.

In any case, for a given member foo it will be initialized by the in class initialization (if any) or by the initialization list (if any) or it will be default initialized. Regardless of the method used to initialize it, that initialization will always happen after another member declared before it and before another member declared after it.

For example:

struct s {
    int a = 1;
    int b = 42;
    int c = 666;
    int d;
    int e;
    s() : e(3), b(123) {
        c = 7;
    }
};

The above will always initialize a first and since it has an in-class initializer, that will be used. It's value will be 1.

b is initialized second. It has an in-class initializer, but the constructors initialization list overrules that. It will be initialized to the value 123.

Then c is initialized to the value 666.

d is uninitialized / or rather; default initialized, which for a int is the same as uninitialized, but for other types like std::string means initialized to an empty string - it depends on the type whether you have a usable value or not.

Then e is initialized to the value 3. This happens last because it is declared last. The order it is listed in in the initialization list of the constructor is irrelevant.

Then the constructor body is executed and c is assigned the value 7. So it is both initialized and subsequently assigned to - this is usually inefficient.

The object construction is now complete.

Jesper Juhl
  • 30,449
  • 3
  • 47
  • 70
  • Your first paragraph contradicts the next two (you simply constructed an example where it doesn't matter). What if `d` had an equal-or-brace-initializer and `b` did not. According to your first statement, the order is still abcde but according to the next parts of your answer, the order is acdbe. – Ben Voigt Jun 24 '20 at 20:42
  • @Ben I don't quite see how my answer is unclear (feel free to edit). The initialization order is *always* abcde, but whether any given element is initialized by the in-class value or the initialization list depends on whether there *is* an entry is the initialization list or not. If there *is* it always wins, if there is not the in-class initialization is used. If I somehow didn't make that clear, feel free to edit and improve my wording. Or if I just completely screwed up something, then please let me know. – Jesper Juhl Jun 24 '20 at 20:47
  • I'm not sure how to make it clear without totally destroying your sentence structure. The problem is that you talk about initializers as a group, members with them as one group and members mentioned in the constructor initializer list as a different group. And in fact there are no groups, each member (actually, each subobject, with base class instances being processed ahead of members) is processed individually and completely before moving onto the next member and applying the same set of rules to it. – Ben Voigt Jun 24 '20 at 20:52
  • @Ben Yes. I agree. Each member (or base object, first) is initialized individually in the order they are declared. The value they are initialized to is either what they get from the constructors initialization list or, if that is not present, the in-class initializer. But it all happens in declaration order. I'm sorry if the answer I posted is unclear. I hope the comments rectify that. I believe I know how this works, but I may lack the language skills to express it properly. Downvote the answer if you feel it + comments is still unclear or misleading. – Jesper Juhl Jun 24 '20 at 20:56
3

Yes, the members will be initialized in the order they are declared in the class.

So when you call Foo(100), a and b will be initialized with the default values, and then c will be initialized to 100.

cigien
  • 57,834
  • 11
  • 73
  • 112