I've always used std::move
to move a std::vector
into an empty one in member initialization lists like this:
class Bar{};
class Foo
{
public:
Foo(std::vector<std::unique_ptr<Bar>>&& t_values)
: m_Values{ std::move(t_values) }
{
}
private:
std::vector<std::unique_ptr<Bar>> m_Values{};
};
I thought that the std::move
in the constructor would clear the t_values
vector, but recently I've discovered a bug that does not clear the t_values
vector
and causes unexpected behaviour e.g. destroying the vector
s elements before they should be (std::swap
would fix this issue). Is it not required by the standard for the moved vector to be empty?
CodePudding user response:
A move results in a "valid but unspecified state":
Moved-from state of library types [lib.types.movedfrom]
Objects of types defined in the C standard library may be moved from.
Move operations may be explicitly specified or implicitly generated. Unless
otherwise specified, such moved-from objects shall be placed in a valid
but unspecified state.
A moved-from vector can certainly be empty, that would be "valid". But nothing in the C standard requires that. In the case of a moved-from vector of std::unique_ptr
s, it would also be "valid" if the moved-from vector remains non-empty, but now has some indeterminate number of default-constructed std::unique_ptr
s (the moved-from vector's size can remain the same, or may be different). The original std::unique_ptr
s are now in the moved-to vector, and the moved-from vector has some default-constructed std::unique_ptr
s. No rules are broken. The moved-from vector is in a "valid" state.
For various practical reasons, it's extremely unlikely for a moved-from vector in any typical C library implementation to behave this way, in this case. That's very unlikely. But it would be valid, if it were the case, provided that the overall state is still valid. It would not be valid for both the moved-from and the moved-to vector of std::unique_ptr
s to end up with std::unique_ptr
s to the same objects.
If you're observing spurious, or extra, object construction or destruction, it must be due to undefined behavior of some other source. There's nothing wrong with the shown code. If there's undefined behavior, it must be in code that's not shown.