C++返回值优化和具名返回值优化是编译器的优化,在大多数情况下能提高性能,但是却难以受程序员控制。C++11中加入了move语义的支持,由此对RVO和NRVO会造成一定影响。下面以一段代码来说明。
RVO和NRVO在分别在copy/move construct,copy/move assignment八种简单情况,测试条件是g++ 4.8.2和clang++ 3.4,默认优化。
#include <iostream>
#include <vector>
#include <string>
struct Test {
Test()
{
//std::cout << "construct a Test object" << std::endl;
}
Test(const Test&)
{
std::cout << "copy construct a Test object" << std::endl;
}
Test& operator=(const Test &t)
{
std::cout << "copy assignment a Test object" << std::endl;
return *this;
}
Test(Test&& t)
{
std::cout << "move construct a Test object" << std::endl;
}
Test& operator=(Test &&t)
{
std::cout << "move assignment a Test object" << std::endl;
return *this;
}
~Test()
{
//std::cout << "destruct a Test object" << std::endl;
}
};
Test getTest()
{
// anonymous object
return Test();
}
Test getTestWithName()
{
// named return value
Test temp;
return temp;
}
int main()
{
std::cout << "==== common case ====" << std::endl;
Test o1;
std::cout << "---- Test copy construct: " << std::endl;
Test o2(o1); // two ways for copy construct
Test o3 = o1;
std::cout << "---- Test move construct: " << std::endl;
Test o4(std::move(o3));
std::cout << "---- Test assignment: " << std::endl;
o2 = o1;
std::cout << "---- Test move assignment: " << std::endl;
Test o5; o5 = std::move(o4);
std::cout << "\n==== test for rvo ===" << std::endl;
std::cout << "---- Test rvo for copy construct: " << std::endl;
Test obj11(getTest());
Test obj1 = getTest();
std::cout << "---- Test rvo for move construct: " << std::endl;
Test obj12(std::move(getTest()));
std::cout << "---- Test rvo for assignment: " << std::endl;
Test obj2; obj2 = getTest();
std::cout << "---- Test rvo move assignment: " << std::endl;
Test obj5; obj5 = std::move(getTest());
std::cout << "\n==== test for nrvo ===" << std::endl;
std::cout << "---- Test nrvo for copy construct: " << std::endl;
Test obj33(getTestWithName());
Test obj3 = getTestWithName();
std::cout << "---- Test nrvo for move construct: " << std::endl;
Test obj34(std::move(getTestWithName()));
std::cout << "---- Test nrvo for assignment: " << std::endl;
Test obj4; obj4 = getTestWithName();
std::cout << "---- Test nrvo move assignment: " << std::endl;
Test obj6; obj6 = std::move(getTestWithName());
return 0;
}
测试结果:
==== common case ====
---- Test copy construct:
copy construct a Test object
copy construct a Test object
---- Test move construct:
move construct a Test object
---- Test assignment:
copy assignment a Test object
---- Test move assignment:
move assignment a Test object
==== test for rvo ===
---- Test rvo for copy construct:
---- Test rvo for move construct:
move construct a Test object
---- Test rvo for assignment:
move assignment a Test object
---- Test rvo move assignment:
move assignment a Test object
==== test for nrvo ===
---- Test nrvo for copy construct:
---- Test nrvo for move construct:
move construct a Test object
---- Test nrvo for assignment:
move assignment a Test object
---- Test nrvo move assignment:
move assignment a Test object
由此可得出几个简单结论:
1.copy construct本身在RVO和NRVO两种情况下被优化了,如果再加上move反而画蛇添足。
2.加入了move assignment后,默认是调用move assignment而不是copy assignment,可以将move assignment注释后测试。
3.对于RVO和NRVO来说,construction的情况编译器优化得比较好了,加入move语义主要是对于assignment有比较大影响