user553702
user553702

Reputation: 2935

Does calling a C++ constructor from another member function/constructor execute the initializer list?

In a C++ object, when you call a constructor from another constructor or member function (after the object has already been constructed), does the initializer list of the constructor you're calling still get executed?

Upvotes: 3

Views: 4204

Answers (4)

In C++11 you can have a constructor delegate work to another constructor in the same class, e.g.1:

#include <iostream>
struct SomeType  {
    int number;

    SomeType(int new_number) : number(new_number) {}
    SomeType() : SomeType(42) {}
};

int main() {
  SomeType a;
  std::cout << a.number << std::endl;
}

In this instance it is forbidden to have an initaliser list after this delegation, e.g. changing the previous example to:

SomeType() : SomeType(42), number(0) {}

is an error.


If the question was "given an inheritance relationship does the initaliser list still get called?" the answer is yes, e.g.

#include <iostream>
struct SomeBase {
  SomeBase(int) {}
};

struct SomeType : SomeBase {
    int number;

    SomeType(int new_number=0) : SomeBase(new_number), number(new_number) {}
};

int main() {
  SomeType a;
  std::cout << a.number << std::endl;
}

This is fine and works exactly how you'd hope.


It's not legal to directly call a constructor from within another constructor and in C++ prior to C++11 there's no constructor delegation allowed either, so something like:

#include <iostream>

struct SomeType {
    int number;

    SomeType(int new_number) : number(new_number) {}
    SomeType() {
      SomeType::SomeType(0); // Error!
    }
};

int main() {
  SomeType a;
  std::cout << a.number << std::endl;
}

Is an error and can't be expressed directly.

The following (which I'd guess is what you had in mind when writing the question) example isn't an error however, but doesn't do what you might hope:

#include <iostream>

struct SomeType {
    int number;

    SomeType(int new_number) : number(new_number) {}
    SomeType() {
      SomeType(0); 
      number = 42;
    }
};

int main() {
  SomeType a;
  std::cout << a.number << std::endl;
}

Here the constructor with no parameters constructs an anonymous temporary instance of SomeType. It's a totally separate instance to the one that the constructor was called for initially. This is perfectly legal, but probably not what you meant to do. If you do this there's a risk that you might create infinite recursion if you're not careful and I think it's probably a good indicator of a design problem if you end up doing something like that!

1 Derived from the Wikipedia C++11 article

Upvotes: 2

Dan Nissenbaum
Dan Nissenbaum

Reputation: 13908

I assume you are referring to calling a base-class constructor from WITHIN the initialization list of a derived class. Assuming this is the case, then the BASE class constructor is executed first (including its initializer list), and THEN the derived class's initializer list is called.

In case you're wondering - the base class constructor is ALWAYS called prior to the initializer list being executed for a derived class, EVEN if the call to the base class constructor appears explicitly in the middle or end of the derived class's initializater list (as well as if it appears at the beginning). The reason is that the items in the initializer list are executed in the order they appear in the class DECLARATION in the class's header file, not in the order they appear in the initializer list in the constructor definition. And, the base class constructor is never declared in the derived class declaration. C++ requires that the base class constructor is ALWAYS called before the derived class constructor - whether the call to the base class constructor appears explicitly in the derived class's initializer list, or not - and no matter where it appears in the initializer list.

Upvotes: 1

cdmh
cdmh

Reputation: 3344

You cannot call a constructor explicitly, only by object construction either via new or on the stack. There are ways to hack it (e.g. placement new) but don't do that, just use two stage construction & initialisation.

Upvotes: 0

John Dibling
John Dibling

Reputation: 101456

Don't call the constructor explicitly from another method, or another constructor.

Use two-stage initialization instead if you really need in, in which you call an Init() type method after constructing the object.

Upvotes: 0

Related Questions