Reputation: 1930
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?
Upvotes: 2
Views: 474
Reputation: 409176
When an exception is thrown, normal execution halts immediately, and the call stack is unwound. until the first valid catch
. For your case it means that as soon as you throw
the continued execution of the foo
and the assignment operator functions are halted and the program goes to the catch
in the main
function, in other words nothing happens that would alter the objects.
Moving a std::string
object leaves the source in a valid but uspecified state. It should be noted that moving is commonly implemented by swapping source and destination, which will explain the behavior you see.
Upvotes: 3