4

I have the following code snippet:

#include <vector>

struct X {
    std::vector<X> v;
    X(std::vector<X> vec) : v{vec} {}
};

int main() {
    X{{}};
}

Compiling and running this snippet locally results in a stack overflow originating from X's constructor. Inspection with gdb shows me that the constructor is somehow recursively calling itself, but that doesn't make sense because I'm not calling it recursively. Why might this be happening and what can I do to fix it?

2
  • 1
    X contains several (vector of) X? Is this a tree structure? Commented Dec 30, 2021 at 22:19
  • @Sebastian yes, it's a recursive tree structure. Commented Dec 30, 2021 at 22:20

1 Answer 1

6

The problem has to do with how C++ chooses which constructor to execute. Notice that X's constructor uses curly-brace syntax in the member initialization list, meaning that it's using list-initialization syntax. According to the C++ reference:

When an object of non-aggregate class type T is list-initialized, two-phase overload resolution takes place.

  • at phase 1, the candidate functions are all initializer-list constructors of T and the argument list for the purpose of overload resolution consists of a single initializer list argument
  • if overload resolution fails at phase 1, phase 2 is entered, where the candidate functions are all constructors of T and the argument list for the purpose of overload resolution consists of the individual elements of the initializer list.

If the initializer list is empty and T has a default constructor, phase 1 is skipped.

In copy-list-initialization, if phase 2 selects an explicit constructor, the initialization is ill-formed (as opposed to all over copy-initializations where explicit constructors are not even considered).

std::vector has an initializer-list constructor as noted here, so this constructor is prioritized in the aforementioned phase 1. In the question, the non-explicit constructor for X means that the provided vector vec can be implicitly converted to an X, and so the vector constructor can be applied. Since this implicit conversion calls X's constructor, you end up with the recursion described above.

To fix this, either mark X's constructor as explicit, or switch to v(vec) syntax in the constructor.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.