C++编译器优化:Copy Elision(省略不必要的拷贝)
2011-10-05 17:56
232 查看
为避免对临时对象进行不必要的拷贝,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编译运行结果如下
返回值优化(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
- 网站优化必要的网络营销工具
- CUDA Fortran不必要数据拷贝
- 关于拷贝构造隐式转换和return时优化的一些思考
- 在 Django REST framework 善用 SerializerMethodField 来优化不必要的查询
- centos7优化启动项,关闭一些不必要开启的服务
- C++中的构造函数与拷贝构造的优化处理
- 模板拷贝【便利贴】Struts性能优化
- string类的浅拷贝优化1
- 轻松搞死VS2008的C++编译器,error PRJ0002,优化编译器遇到问题需要关闭
- memcpy内存拷贝的改进与优化 (转)
- 黄聪:WordPress wp_head()优化:去除不必要的元素标签(转)
- 内存拷贝的优化方法(1)[转]
- Angular移除不必要的$watch之性能优化
- elasticsearch 索引搜索和索引性能优化配置——思路:去掉不必要的数据,减小数据的磁盘空间占用,同时提升性能
- 对象拷贝类PropertyUtils,BeanUtils,BeanCopier的技术沉淀(3)------优化方案
- 内存拷贝的优化方法(2)
- 由一道题目想到的C++编译器优化问题
- const&&运算符的内联&静态成员&友元&N中构造拷贝构造的优化
- 编写高质量代码改善C#程序的157个建议[为类型输出格式化字符串、实现浅拷贝和深拷贝、用dynamic来优化反射]