I came across the following problem, with two classes X
and Y
where Y
has a member of type X
If I then:
- create a vector of objects of type
Y
viastd::vector<Y> list = {{}}
- and
Y
has a defaulted default constructor
One of the instances of type X
will be destroyed twice. Even when using rule of three (or five).
It does not happen, if I either create the vector via {Y{}}
or define a user supplied default constructor for Y
.
See the console output of the following example:
#include <iostream>
#include <vector>
class X
{
public:
X()
{
std::cout << "constructed " << this << std::endl;
}
~X()
{
std::cout << "deleted " << this << std::endl;
}
X(const X& other)
{
std::cout << "copy constructed " << &other << " to " << this << std::endl;
}
};
class Y
{
public:
//Y(){}; // works
Y() = default; // doesn't work
~Y() = default;
Y(const Y& y) = default; // copy constructor
Y& operator=(const Y& y) = default; // copy assignment
// Y(Y&& other) noexcept = default; // move constructor
// Y& operator=(Y&& other) noexcept = default; // move assignment
private:
X x;
};
int main()
{
std::cout << "start" << std::endl;
std::vector<Y> list = {{}}; // doesn't work
//std::vector<Y> list = {Y{}}; // works
std::cout << "done" << std::endl;
return 0;
}
Outputs
start
constructed 000000271CAFFCD0
copy constructed 000000271CAFFCD0 to 000001727F7145B0
deleted 000000271CAFFCD0
deleted 000000271CAFFCD0
done
deleted 000001727F7145B0
https://godbolt.org/z/vscP4TexE
This is only reproducable in MSVC.
Am I missing something or is this a compiler bug?
Edit
Thanks for the hint about the missing return statements. I added them, but get the same results.
I did enable warnings, but it only shows that the unreferenced inline functions are removed.
Edit 2
Since they are unused, I removed copy and move constructors and assignment operators from the example.
Edit 3
Adapted Output to the new code example. It still contains the double delete. Note that MSVC is a bit flakey on godbolt and it sometimes does not compile the example.