Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why throw local variable invokes moves constructor?

Recently, I've "played" with rvalues to understand their behavior. Most result didn't surprize me, but then I saw that if I throw a local variable, the move constructor is invoked.

Until then, I thought that the purpose of move semantics rules is to guarantee that object will move (and become invalid) only if the compiler can detect that it will not be used any more (as in temporary objects), or the user promise not to use it (as in std::move).

However, in the following code, none of this condition held, and my variable is still being moved (at least on g++ 4.7.3).

Why is that?

#include <iostream>
#include <string>
using namespace std;

int main() {
    string s="blabla";
    try {
        throw s;
    }
    catch(...) {
        cout<<"Exception!\n";
    }
    cout<<s; //prints nothing
}
like image 424
asaelr Avatar asked Jun 05 '13 11:06

asaelr


2 Answers

C++ standard says (15.1.3):

Throwing an exception copy-initializes (8.5, 12.8) a temporary object, called the exception object. The temporary is an lvalue and is used to initialize the variable named in the matching handler (15.3).

This paragraph may be also relevant here (12.8.31):

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object, and the destruction of that object occurs at the later of the times when the two objects would have been destroyed without the optimization. This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):

(...)

in a throw-expression, when the operand is the name of a non-volatile automatic object (other than a function or catch-clause parameter) whose scope does not extend beyond the end of the innermost enclosing try-block (if there is one), the copy/move operation from the operand to the exception object (15.1) can be omitted by constructing the automatic object directly into the exception object

Checked in Visual Studio 2012, effect:

Exception!
blabla

It looks like a bug in GCC indeed.

like image 93
Spook Avatar answered Nov 18 '22 11:11

Spook


In the given case, it is probably a compiler bug, because the variable thrown (and moved from) is referenced afterwards.

In general case invoking move on throw is conceptually same as moving on return. It is good to invoke move automatically when it is known that the variable could not be referenced after the given point (throw or return).

like image 37
Juraj Blaho Avatar answered Nov 18 '22 11:11

Juraj Blaho