Reputation: 975
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?
Upvotes: 4
Views: 203
Reputation: 975
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.
Upvotes: 6