How to enforce move semantics when a vector grows?

Bertwim van Beest picture Bertwim van Beest · Nov 3, 2011 · Viewed 17.2k times · Source

I have a std::vector of objects of a certain class A. The class is non-trivial and has copy constructors and move constructors defined.

std::vector<A>  myvec;

If I fill-up the vector with A objects (using e.g. myvec.push_back(a)), the vector will grow in size, using the copy constructor A( const A&) to instantiate new copies of the elements in the vector.

Can I somehow enforce that the move constructor of class A is beging used instead?

Answer

Johan Lundberg picture Johan Lundberg · Jan 14, 2012

You need to inform C++ (specifically std::vector) that your move constructor and destructor does not throw, using noexcept. Then the move constructor will be called when the vector grows.

This is how to declare and implement a move constuctor that is respected by std::vector:

A(A && rhs) noexcept { 
  std::cout << "i am the move constr" <<std::endl;
  ... some code doing the move ...  
  m_value=std::move(rhs.m_value) ; // etc...
}

If the constructor is not noexcept, std::vector can't use it, since then it can't ensure the exception guarantees demanded by the standard.

For more about what's said in the standard, read C++ Move semantics and Exceptions

Credit to Bo who hinted that it may have to do with exceptions. Also consider Kerrek SB's advice and use emplace_back when possible. It can be faster (but often is not), it can be clearer and more compact, but there are also some pitfalls (especially with non-explicit constructors).

Edit, often the default is what you want: move everything that can be moved, copy the rest. To explicitly ask for that, write

A(A && rhs) = default;

Doing that, you will get noexcept when possible: Is the default Move constructor defined as noexcept?

Note that early versions of Visual Studio 2015 and older did not support that, even though it supports move semantics.