Search code examples
c++constructordefault-value

default value in struct and the constructor order


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?
  }
}

Solution

  • 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.