Wherever I read in the internet, it is strongly adviced that if I want my class to be working well with std::vector
(i.e. move semantics from my class were used by std::vector
) I should delcare move constructor as 'noexcept' ( or noexcept(true)
).
std::vector
use it even though I marked it noexcept(false)
as an experiment?#include <iostream>
#include <vector>
using std::cout;
struct T
{
T() { cout <<"T()\n"; }
T(const T&) { cout <<"T(const T&)\n"; }
T& operator= (const T&)
{ cout <<"T& operator= (const T&)\n"; return *this; }
~T() { cout << "~T()\n"; }
T& operator=(T&&) noexcept(false)
{ cout <<"T& operator=(T&&)\n"; return *this; }
T(T&&) noexcept(false)
{ cout << "T(T&&)\n"; }
};
int main()
{
std::vector<T> t_vec;
t_vec.push_back(T());
}
T()
T(T&&)
~T()
~T()
Why ? What did I do wrong ?
Compiled on gcc 4.8.2 with CXX_FLAGS set to:
--std=c++11 -O0 -fno-elide-constructors
You did nothing wrong.
You just wrongly thought push_back
had to avoid a throwing move-ctor: It does not, at least for constructing the new element.
The only place where throwing move-ctors / move-assignments must be shunned is on re-allocation of the vector, to avoid having half the elements moved, and the rest in their original places.
The function has the strong exception-safety guarantee:
Either the operation succeeds, or it fails and nothing has changed.
If vector::push_back
needs to reallocate its storage it first allocates new memory, then move constructs the new element into the last position. If that throws the new memory is deallocated, and nothing has changed, you get the strong exception-safety guarantee even if the move constructor can throw.
If it doesn't throw, the existing elements are transferred from the original storage to the new storage, and here is where the noexcept
specification of the move constructor matters. If moving might throw and the type is CopyConstructible then the existing elements will be copied instead of moved.
But in your test you're only looking at how the new element is inserted into the vector, and it is always OK to use a throwing constructor for that step.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With