I have the following code:
SomeClass func()
{
SomeClass someObject;
someObject.mutate("some text");
return someObject;
}
int main()
{
func();
return 0;
}
where SomeClass only logs something in the constructors so I can verify what is being called.
With a release build I have the following ouptut:
default constructor
which makes sense due to copy/move elision. I wanted Return Value Optimization turned off. With the debug build I have the following output:
default constructor
move constructor
where I think that I can safely assume the NRVO si off. I am really wondering why the move constructor is being called instead of the copy constructor. My (probably wrong) understanding is that since someObject in func is a lvalue then the return object should be initialized using the copy constructor and not the move constructor.
What am I missing? Can someone points to the paragraph in standard where that case is elucidated?
From cppreference.com for return [expression];
:
If
[expression]
is an lvalue expression that is the (possibly parenthesized) name of an automatic storage duration object declared in the body or as a parameter of the innermost enclosing function or lambda expression, then overload resolution to select the constructor to use for initialization of the returned value is performed twice: first as if[expression]
were an rvalue expression (thus it may select the move constructor), and if no suitable conversion is available, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object's type (possibly cv-qualified), overload resolution is performed a second time, with[expression]
considered as an lvalue (so it may select the copy constructor taking a reference to non-const).
In short, since C++11, a return
statement will prefer to use the move constructor if possible and fallback to the copy constructor.