“return value optimization” is a common technique of copy elision whose target is eliminating unnecessary copying of objects. Check the following example:
#include <iostream>
using namespace std;
class Foo {
public:
Foo() {cout<<"default constructor is called"<<endl;}
Foo(const Foo& other) {cout<<"copy constructor is called"<<endl;}
Foo(Foo&& other) {cout<<"move constructor is called"<<endl;}
};
Foo func()
{
Foo f;
return f;
}
int main()
{
Foo a = func();
return 0;
}
The compiler is clang 5.0.1
:
# c++ --version
OpenBSD clang version 5.0.1 (tags/RELEASE_501/final) (based on LLVM 5.0.1)
Target: amd64-unknown-openbsd6.3
Thread model: posix
InstalledDir: /usr/bin
Build an execute it:
# c++ -std=c++11 test.cpp
# ./a.out
default constructor is called
You may expect Foo
‘ copy constructor is called at least once:
Foo a = func();
However, the reality is that compiler may be clever enough to know the content in local variable f
of func()
will be finally copied to a
, so it creates a
first, and pass a
into func()
, like this:
Foo a;
func(&a);
Let’s modify the program:
#include <iostream>
using namespace std;
class Foo {
public:
Foo() {cout<<"default constructor is called"<<endl;}
Foo(const Foo& other) {cout<<"copy constructor is called"<<endl;}
Foo(Foo&& other) {cout<<"move constructor is called"<<endl;}
};
Foo func(Foo f)
{
return f;
}
int main()
{
Foo a;
Foo b = func(a);
return 0;
}
This time, the temp variable f
of func()
is a parameter. Build and run it:
# c++ -std=c++11 test.cpp
# ./a.out
default constructor is called
copy constructor is called
move constructor is called
the temp variable f
of func()
is constructed by copy constructor:
Foo b = func(a);
In above statement, the func(a)
returns a temporary variable, which is a rvalue, so the Foo
‘s move constructor is used to construct b
. If Foo
doesn’t define move constructor:
Foo(Foo&& other) {cout<<"move constructor is called"<<endl;}
Then “Foo b = func(a);
” will trigger copy constructor to initialize b
.