Consider the following program:
#include <vector>
#include <iostream>
class A {
int x;
public:
A(int n) noexcept : x(n) { std::cout << "ctor with value\n"; }
A(const A& other) noexcept : x(other.x) { std::cout << "copy ctor\n"; }
A(A&& other) noexcept : x(other.x) { std::cout << "move ctor\n"; }
~A() { std::cout << "dtor\n"; } // (*)
};
int main()
{
std::vector<A> v;
v.emplace_back(123);
v.emplace_back(456);
}
If I run the program, I get (GodBolt):
ctor with value
ctor with value
move ctor
dtor
dtor
dtor
... which is in line with what I would expect. However, if on line (*)
I mark the destructor as potentially throwing, I then get :
ctor with value
ctor with value
copy ctor
dtor
dtor
dtor
... i.e. the copy ctor is used instead of the move ctor. Why is this the case? It doesn't seem copying prevents destructions that moving would necessitate.
Related questions:
- are std::vector required to use move instead of copy?
- How to enforce move semantics when a vector grows?
- Vector reallocation uses copy instead of move constructor
CodePudding user response:
This is LWG2116. The choice between moving and copying the elements is often expressed as std::is_nothrow_move_constructible
, i.e. noexcept(T(T&&))
, which also checks the destructor.