Copying elision for can occur only in a few specific situations, the most common of which is copying temporary (the rest return local residents and throw / catch exceptions). Your code is not generated temporarily, so the copy is not deleted.
The copy constructor is called because foo does not have a move constructor (move constructors are implicitly generated for classes with explicit copy constructors), so std::move(a) matches the constructor foo(const foo &rhs) (which is used to build the function argument).
Copying the lvalue value can be undone in the following situations (although there is no way to force the compiler to throw an exception):
foo fn() { foo localAutomaticVariable; return localAutomaticVariable; //Copy to construct return value may be elided } int main() { try { foo localVariable; throw localVariable; //The copy to construct the exception may be elided } catch(...) {} }
If you want to avoid copying when passing arguments to a function, you can use a move constructor that imposes object resources on it:
class bar { public: bar() {cout<<"ctor"<<endl;}; bar(const bar &rhs) {cout<<"copy ctor"<<endl;} bar(bar &&rhs) {cout<<"move ctor"<<endl;} }; void fn(bar a) { }
In addition, whenever copy permission is allowed but does not occur, the move constructor will be used if it is available.
source share