A type X
has a non-trivial move-constructor, which is not declared noexcept (ie. it can throw):
#include <iostream>
#include <vector>
#include <memory>
struct X {
X()=default;
X(X&&) { std::cout << "X move constructed\n"; } // not 'noexcept'
X(const X&) { std::cout << "X copy constructed\n"; }
};
struct test {
X x;
};
int main()
{
static_assert(std::is_nothrow_move_constructible_v<X> == false);
static_assert(std::is_nothrow_move_constructible_v<test> == false);
std::vector<test> v(1);
v.push_back(test{}); // internal object re-allocation, uses copy-constructor
}
When calling push_back
on a vector<test>
, internal reallocations cause existing objects to be copied, which is expected.
The output is:
X move constructed
X copy constructed
Apparently, the second line is related to internal object reallocation.
Now an unrelated std::unique_ptr<int>
is added to test
:
struct test {
std::unique_ptr<int> up;
X x;
};
The output becomes:
X move constructed
X move constructed
Why is internal reallocation using the move-constructor this time ?
Technically, X(X&&)
can still throw an exception; wouldn't that violate the strong exception guarantee of push_back
?
compiler is gcc 11.2.1 and/or clang 12.0.1