Consider:
struct Boo { Boo (std::string v) : src {v} {} Boo (const Boo&) = delete; Boo& operator= (const Boo&) = delete; Boo (Boo&& b) : src {std::move (b.src)} {} Boo& operator= (Boo&& b) { if (this != &b) { foo (); src = std::move (b.src); } return *this; } void show () { std::cout << "|" << src << "|" << std::endl; } void foo () { throw 1; } std::string src {}; }; and usage:
int main(int argc, char** argv) { Boo s {"Boo1"}; Boo p {"Boo2"}; try { p = std::move (s); // (X) } catch (...) {} s.show (); p.show (); return 0; } And outputs look like this:
If foo() is invoked in move assignment operator
|Boo1| |Boo2| If foo() is not invoked
|Boo2| |Boo1| Questions:
What happens with s when exception is thrown in move assignment operator? Does it have previous content just like before using std::move() in line (X), or the content is completely moved to the b (function parameter)?
Why in both cases outputs show that content is still in std::string objects?
noexceptbecause otherwise the STL will just copy the objects to prevent inconsistent state.nothrow. I couldn't find an explicit definition for this, but it follows from the defined semantics in case an exception occurs. Then, resize must restore the old state of the vector, but that cannot be done when the (destructive) move threw. So,resizecan only use nothrow move. There is a special helper move_if_noexcept defined in the standard for this: en.cppreference.com/w/cpp/utility/move_if_noexcept.