C++编译器优化:Copy Elision
2013-05-13 21:36
225 查看
为避免对临时对象进行不必要的拷贝,C++编译器常使用一种名为Copy Ellision(拷贝去除)的优化技术,该技术至少包括以下两项内容:
返回值优化(RVO),即通过将返回值所占空间的分配地点从被调用端转移至调用端的手段来避免拷贝操作。
返回值优化包括具名返回值优化(NRVO)与无名返回值优化(URVO),两者的区别在于返回值是具名的局部变量还是无名的临时对象。
右值拷贝优化,当某一个类类型的临时对象被拷贝赋予同一类型的另一个对象时,通过直接利用该临时对象的方法来避免拷贝操作。
这项优化只能用于右值(临时对象),不能用于左值。
如果需要测试编译器是否应用了Copy Ellision优化技术,可使用以下代码(摘自cppnext)。
代码说明
lvalue()函数返回struct X类型的全局变量lvalue_的引用,故lvalue()函数返回左值,可用于测试右值拷贝优化。
rvalue()函数返回struct X类型的构造器所构建的临时对象,故rvalue()函数返回右值,可用于测试右值拷贝优化。
nrvo_source()函数返回struct X类型的局部变量a,故nrvo_source()函数可用于测试具名返回值优化。
urvo_source()函数返回struct X类型的构造器所构建的临时对象,故urvo_source()函数可用于测试无名返回值优化。
第109,110行分别用左右值来测试类对象直接初始化中的右值拷贝优化。
第112,113行分别用左右值来测试类对象拷贝初始化中的右值拷贝优化。
第115,116行分别用左右值来测试普通函数实参中的右值拷贝优化。
第118,119行分别用于测试具名返回值优化与无名返回值优化。
Windows平台下使用gcc4.6.1编译运行结果如下
X0: construct
Direct initialization from lvalue
X a(( lvalue() ))
===========
X1: <- X0: **copy**
X1: destroy
-----------
1/1 possible copies made
0/0 possible elisions performed
Direct initialization from rvalue
X a(( rvalue() ))
===========
X2: construct
X2: destroy
-----------
0/1 possible copies made
1/1 possible elisions performed
Copy initialization from lvalue
X a = lvalue()
===========
X3: <- X0: **copy**
X3: destroy
-----------
1/1 possible copies made
0/0 possible elisions performed
Copy initialization from rvalue
X a = rvalue()
===========
X4: construct
X4: destroy
-----------
0/1 possible copies made
1/1 possible elisions performed
Pass lvalue by value
sink( lvalue() )
===========
X5: <- X0: **copy**
->: sink
<-: sink
X5: destroy
-----------
1/1 possible copies made
0/0 possible elisions performed
Pass rvalue by value
sink( rvalue() )
===========
X6: construct
->: sink
<-: sink
X6: destroy
-----------
0/1 possible copies made
1/1 possible elisions performed
Named return value optimization (NRVO)
nrvo_source()
===========
->: nrvo_source
X7: construct
<-: nrvo_source
X7: destroy
-----------
0/1 possible copies made
1/1 possible elisions performed
Unnamed return value optimization (URVO)
urvo_source()
===========
->: urvo_source
X8: construct
<-: urvo_source
X8: destroy
-----------
0/1 possible copies made
1/1 possible elisions performed
Return value used as ctor arg
X a(urvo_source())
===========
->: urvo_source
X9: construct
<-: urvo_source
X9: destroy
-----------
0/2 possible copies made
2/2 possible elisions performed
Return rvalue passed by value
identity( rvalue() )
===========
X10: construct
->: identity
X11: <- X10: **copy**
<-: identity
X11: destroy
X10: destroy
-----------
1/2 possible copies made
1/2 possible elisions performed
*** 1 possible elisions missed! ***
X0: destroy
返回值优化(RVO),即通过将返回值所占空间的分配地点从被调用端转移至调用端的手段来避免拷贝操作。
返回值优化包括具名返回值优化(NRVO)与无名返回值优化(URVO),两者的区别在于返回值是具名的局部变量还是无名的临时对象。
右值拷贝优化,当某一个类类型的临时对象被拷贝赋予同一类型的另一个对象时,通过直接利用该临时对象的方法来避免拷贝操作。
这项优化只能用于右值(临时对象),不能用于左值。
如果需要测试编译器是否应用了Copy Ellision优化技术,可使用以下代码(摘自cppnext)。
#include <iostream> struct X { X() : id(instances++) { std::cout << "X" << id << ": construct\n"; } X(X const& rhs) : id(instances++) { std::cout << "X" << id << ": <- " << "X" << rhs.id << ": **copy**\n"; ++copies; } // This particular test doesn't exercise assignment, but for // completeness: X& operator=(X const& rhs) { std::cout << "X" << id << ": <- " << "X" << rhs.id << ": assign\n"; } ~X() { std::cout << "X" << id << ": destroy\n"; } unsigned id; static unsigned copies; static unsigned instances; }; unsigned X::copies = 0; unsigned X::instances = 0; #define CHECK_COPIES( stmt, min, max, comment ) \ { \ unsigned const old_copies = X::copies; \ \ std::cout << "\n" comment "\n" #stmt "\n===========\n"; \ { \ stmt; \ } \ unsigned const n = X::copies - old_copies; \ if (n > max) \ std::cout << "*** max is too low or compiler is buggy ***\n"; \ if (n < min) \ std::cout << "*** min is too high or compiler is buggy ***\n"; \ \ std::cout << "-----------\n" \ << n << "/" << max \ << " possible copies made\n" \ << max - n << "/" << max - min \ << " possible elisions performed\n\n"; \ \ if (n > min) \ std::cout << "*** " << n - min \ << " possible elisions missed! ***\n"; \ } struct trace { trace(char const* name) : name(name) { std::cout << "->: " << name << "\n"; } ~trace() { std::cout << "<-: " << name << "\n"; } char const* name; }; void sink(X a) { trace t("sink"); } X nrvo_source() { trace t("nrvo_source"); X a; return a; } X urvo_source() { trace t("urvo_source"); return X(); } X identity(X a) { trace t("identity"); return a; } X lvalue_; X& lvalue() { return lvalue_; } typedef X rvalue; int main() { // Double parens prevent "most vexing parse" CHECK_COPIES( X a(( lvalue() )), 1, 1, "Direct initialization from lvalue"); CHECK_COPIES( X a(( rvalue() )), 0, 1, "Direct initialization from rvalue"); CHECK_COPIES( X a = lvalue(), 1, 1, "Copy initialization from lvalue" ); CHECK_COPIES( X a = rvalue(), 0, 1, "Copy initialization from rvalue" ); CHECK_COPIES( sink( lvalue() ), 1, 1, "Pass lvalue by value" ); CHECK_COPIES( sink( rvalue() ), 0, 1, "Pass rvalue by value" ); CHECK_COPIES( nrvo_source(), 0, 1, "Named return value optimization (NRVO)" ); CHECK_COPIES( urvo_source(), 0, 1, "Unnamed return value optimization (URVO)" ); // Just to prove these things compose properly CHECK_COPIES( X a(urvo_source()), 0, 2, "Return value used as ctor arg" ); // Expect to miss one possible elision here CHECK_COPIES( identity( rvalue() ), 0, 2, "Return rvalue passed by value" ); }
代码说明
lvalue()函数返回struct X类型的全局变量lvalue_的引用,故lvalue()函数返回左值,可用于测试右值拷贝优化。
rvalue()函数返回struct X类型的构造器所构建的临时对象,故rvalue()函数返回右值,可用于测试右值拷贝优化。
nrvo_source()函数返回struct X类型的局部变量a,故nrvo_source()函数可用于测试具名返回值优化。
urvo_source()函数返回struct X类型的构造器所构建的临时对象,故urvo_source()函数可用于测试无名返回值优化。
第109,110行分别用左右值来测试类对象直接初始化中的右值拷贝优化。
第112,113行分别用左右值来测试类对象拷贝初始化中的右值拷贝优化。
第115,116行分别用左右值来测试普通函数实参中的右值拷贝优化。
第118,119行分别用于测试具名返回值优化与无名返回值优化。
Windows平台下使用gcc4.6.1编译运行结果如下
X0: construct
Direct initialization from lvalue
X a(( lvalue() ))
===========
X1: <- X0: **copy**
X1: destroy
-----------
1/1 possible copies made
0/0 possible elisions performed
Direct initialization from rvalue
X a(( rvalue() ))
===========
X2: construct
X2: destroy
-----------
0/1 possible copies made
1/1 possible elisions performed
Copy initialization from lvalue
X a = lvalue()
===========
X3: <- X0: **copy**
X3: destroy
-----------
1/1 possible copies made
0/0 possible elisions performed
Copy initialization from rvalue
X a = rvalue()
===========
X4: construct
X4: destroy
-----------
0/1 possible copies made
1/1 possible elisions performed
Pass lvalue by value
sink( lvalue() )
===========
X5: <- X0: **copy**
->: sink
<-: sink
X5: destroy
-----------
1/1 possible copies made
0/0 possible elisions performed
Pass rvalue by value
sink( rvalue() )
===========
X6: construct
->: sink
<-: sink
X6: destroy
-----------
0/1 possible copies made
1/1 possible elisions performed
Named return value optimization (NRVO)
nrvo_source()
===========
->: nrvo_source
X7: construct
<-: nrvo_source
X7: destroy
-----------
0/1 possible copies made
1/1 possible elisions performed
Unnamed return value optimization (URVO)
urvo_source()
===========
->: urvo_source
X8: construct
<-: urvo_source
X8: destroy
-----------
0/1 possible copies made
1/1 possible elisions performed
Return value used as ctor arg
X a(urvo_source())
===========
->: urvo_source
X9: construct
<-: urvo_source
X9: destroy
-----------
0/2 possible copies made
2/2 possible elisions performed
Return rvalue passed by value
identity( rvalue() )
===========
X10: construct
->: identity
X11: <- X10: **copy**
<-: identity
X11: destroy
X10: destroy
-----------
1/2 possible copies made
1/2 possible elisions performed
*** 1 possible elisions missed! ***
X0: destroy
相关文章推荐
- C++编译器优化:Copy Elision(省略不必要的拷贝)
- EBO,c++编译器有empty继承优化(编译期)
- 编译器自动优化——为什么我的C++编译器不调用拷贝构造函数了?
- C++编译器到底能帮我们把代码优化到什么程度?
- 轻松搞死VS2008的C++编译器,error PRJ0002,优化编译器遇到问题需要关闭
- C++编译器的递归深度与程序优化思考
- C++编译器到底能帮我们把代码优化到什么程度?
- 阐述C++编译器变量进行优化说明
- C++编译器到底能帮我们把代码优化到什么程度?
- 由一道题目想到的C++编译器优化问题
- C++编译器优化-返回值优化
- C++编译器到底能帮我们把代码优化到什么程度?
- 试验网站#1搜索引擎优化收录情况记录(断续运行)2007-8-16
- 优化网站性能 提高网站速度访问速度的14条实践
- 修改注册表优化加速windows系统开关机
- sql 百万级数据库优化方案【轉】
- 页面性能优化
- 嵌入式C代码优化方案
- 优化网站设计(十):最小化JAVASCRIPT和CSS
- web前端性能优化总结