RVO,是Return Value Optimization。这是在函数返回返回值的时候编译器所做出的优化,是C++11标准的一部分,C++11称之为copy elision。
在第一次编写的函数里面,编译器明确知道函数会返回哪一个局部对象,那么编译器会把存储这个局部对象的地址和存储返回值临时对象的地址进行复用,也就是说避免了从局部对象到临时对象的拷贝操作。这就是RVO。
实验
实验1
#include <iostream>struct Foo { Foo() { std::cout << “Foo()” << std::endl; } Foo(const Foo&) { std::cout << “Foo(const Foo&)” << std::endl; } // Foo(const Foo&&) { // std::cout << “Foo(const Foo&&)” << std::endl; // } Foo& operator = (const Foo&) { std::cout << “operator=(const Foo&)” << std::endl; return *this; } Foo& operator = (const Foo&&) { std::cout << “operator=(const Foo&&)” << std::endl; return *this; } ~Foo() { std::cout << “~Foo” << std::endl; }};Foo test1() { Foo f1; return f1;}Foo test2() { if (true) { Foo f1; return f1; } if (false) { Foo f1; return f1; }}int main() { Foo a = test1(); // const Foo& f = test2(); // Foo f = test2(); // std::cout << “hello edn” << std::endl; return 0;}
输出:
Foo() # f1 临时对象构造~Foo # 临时对象析构
实验二
让编译器在编译时期无法知道返回的临时对象
#include <iostream>struct Foo { Foo() { std::cout << “Foo()” << std::endl; } Foo(const Foo&) { std::cout << “Foo(const Foo&)” << std::endl; } Foo(const Foo&&) { std::cout << “Foo(const Foo&&)” << std::endl; } Foo& operator = (const Foo&) { std::cout << “operator=(const Foo&)” << std::endl; return *this; } Foo& operator = (const Foo&&) { std::cout << “operator=(const Foo&&)” << std::endl; return *this; } ~Foo() { std::cout << “~Foo” << std::endl; }};Foo test1() { Foo f1; return f1;}Foo test2() { if (true) { Foo f1; return f1; } if (false) { Foo f1; return f1; }}int main() { // test1(); // const Foo& f = test2(); Foo f = test2(); // std::cout << “hello edn” << std::endl; return 0;}
输出:
Foo() # f1临时对象构造Foo(const Foo&&) # f1 临时对象拷贝到返回值~Foo ~Foo 关闭RVO g++ class_inhert.cpp -std=c++14 -fno-elide-constructors
重复实验1:
Foo() # f1 临时对象构造Foo(const Foo&&) # f1 右值构造返回值临时对象~FooFoo(const Foo&&) # 通过返回值构造 a~Foo~Foo
重复实验二
Foo()Foo(const Foo&&)~FooFoo(const Foo&&)~Foo~Foo
新增实验3
test1 函数返回值改成右值, 返回类型是右值引用,没有临时对象的消耗,但是仍不可取,因为右值引用的对对象在使用前已经析构了。
#include <iostream>struct Foo { Foo() { std::cout << “Foo()” << std::endl; } Foo(const Foo&) { std::cout << 香港vps “Foo(const Foo&)” << std::endl; } // Foo(const Foo&&) { // std::cout << “Foo(const Foo&&)” << std::endl; // } Foo& operator = (const Foo&) { std::cout << “operator=(const Foo&)” << std::endl; return *this; } Foo& operator = (const Foo&&) { std::cout << “operator=(const Foo&&)” << std::endl; return *this; } ~Foo() { std::cout << “~Foo” << std::endl; } void like() { std::cout << “like” << std::endl; }};Foo&& test1() { Foo f1; return std::move(f1);}Foo test2() { if (true) { Foo f1; return f1; } if (false) { Foo f1; return f1; }}int main() { Foo&& a= test1(); // const Foo& f = test2(); // { // const Foo& f = test2(); // } a.like(); std::cout << “hello edn” << std::endl; return 0;}
输出:
Foo() # 临时对象构造~Foo # 临时对象析构,在使用前已经析构like # hello edn
?新增实验4:
返回值是右值,返回类型是类,??
#include <iostream>struct Foo { Foo() { std::cout << “Foo()” << std::endl; } Foo(const Foo&) { std::cout << “Foo(const Foo&)” << std::endl; } Foo(const Foo&&) { std::cout << “Foo(const Foo&&)” << std::endl; } Foo& operator = (const Foo&) { std::cout << “operator=(const Foo&)” << std::endl; return *this; } Foo& operator = (const Foo&&) { std::cout << “operator=(const Foo&&)” << std::endl; return *this; } ~Foo() { std::cout << “~Foo” << std::endl; } void like() { std::cout << “like” << std::endl; }};Foo test1() { Foo f1; return std::move(f1);}Foo test2() { if (true) { Foo f1; return f1; } if (false) { Foo f1; return f1; }}int main() { Foo&& a = test1(); // Foo a = test1(); // const Foo& f = test2(); // { // const Foo& f = test2(); // } // a.like(); std::cout << “hello edn” << std::endl; return 0;}
输出:
Foo() # f1 临时对象构造Foo(const Foo&&) # 返回值右值拷贝构造~Foohello edn~Foo