c++ rvo vs std::move
To summarize, RVO is a compiler optimization technique, while std::move is just an rvalue cast, which also instructs the compiler that it's eligible to move the object. The price of moving is lower than copying but higher than RVO, so never apply std::move to local objects if they would otherwise be eligible for the RVO.
#include <iostream> #include <chrono> #include <unordered_map> class BigObject { public: BigObject() { std::cout << "constructor. " << std::endl; } ~BigObject() { std::cout << "destructor."<< std::endl; } BigObject(const BigObject&) { std::cout << "copy constructor." << std::endl; } BigObject(BigObject&&) { std::cout << "move constructor"<< std::endl; } }; struct info { std::string str; std::unordered_map <int, std::string> umap; }; int64_t get_current_time_ns() { std::chrono::nanoseconds ss = std::chrono::high_resolution_clock::now().time_since_epoch(); int64_t tt = ss.count(); std::cout<<"current time:"<<tt<<std::endl; return tt; } std::string get_st_v1() { std::string st; st = "ttppppppppppppppppppppppppppppppppppppppppppppppppppppppppp"; return st; } std::string get_st_v2() { std::string st; st = "ttppppppppppppppppppppppppppppppppppppppppppppppppppppppppp"; return std::move(st); } info get_info_v1() { info ifo; ifo.str = "ttppppppppppppppppppppppppppppppppppppppppppppppppppppppppp"; ifo.umap.insert(std::make_pair<int, std::string>(6, "eggs")); return ifo; } info get_info_v2() { info ifo; ifo.str = "ttppppppppppppppppppppppppppppppppppppppppppppppppppppppppp"; ifo.umap.insert(std::make_pair<int, std::string>(6, "eggs")); return std::move(ifo); } BigObject foo(int n) { BigObject localObj; return localObj; } int main() { auto f = foo(1); int64_t t_1= get_current_time_ns(); std::cout<<"test rvo:"<<std::endl; for(int i = 0; i< 100000; i++) { std::string d1 = get_st_v1(); } int64_t t_2= get_current_time_ns(); std::cout<<"v1 time cost:"<<t_2-t_1<<std::endl; std::cout<<"test move:"<<std::endl; for(int j = 0; j< 100000; j++) { std::string d2 = get_st_v2(); } int64_t t_3= get_current_time_ns(); std::cout<<"v2 time cost:"<<t_3-t_2<<std::endl; std::cout<<"info test rvo:"<<std::endl; for(int m = 0; m< 100000; m++) { info d3 = get_info_v1(); } int64_t t_4= get_current_time_ns(); std::cout<<"info v1 time cost:"<<t_4-t_3<<std::endl; std::cout<<"info test move:"<<std::endl; for(int n = 0; n< 100000; n++) { info d4 = get_info_v2(); } int64_t t_5= get_current_time_ns(); std::cout<<"info v2 time cost:"<<t_5-t_4<<std::endl; return 0; }
Result
constructor. current time:1568273863513694551 test rvo: current time:1568273863517139874 v1 time cost:3445323 test move: current time:1568273863521213442 v2 time cost:4073568 info test rvo: current time:1568273863574775754 info v1 time cost:53562312 info test move: current time:1568273863641223923 info v2 time cost:66448169 destructor.
Reference
https://stackoverflow.com/questions/17473753/c11-return-value-optimization-or-move