经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
详解C++编译器优化技术
来源:jb51  时间:2021/6/7 10:29:30  对本文有异议

前言

注1:vc6、vs没有提供编译选项来关闭该优化,无论是debug还是release都会进行RVO和复制省略优化

注2:vc6、vs2005以下及vs2005+ Debug上不支持NRVO优化,vs2005+ Release支持NRVO优化

注3:g++支持这三种优化,并且可通过编译选项:-fno-elide-constructors来关闭优化

RVO

  1. #include <stdio.h>
  2. class A
  3. {
  4. public:
  5. A()
  6. {
  7. printf("%p construct\n", this);
  8. }
  9. A(const A& cp)
  10. {
  11. printf("%p copy construct\n", this);
  12. }
  13. ~A()
  14. {
  15. printf("%p destruct\n", this);
  16. }
  17. };
  18.  
  19. A GetA()
  20. {
  21. return A();
  22. }
  23.  
  24. int main()
  25. {
  26. {
  27. A a = GetA();
  28. }
  29.  
  30. return 0;
  31. }

在g++和vc6、vs中,上述代码仅仅只会调用一次构造函数和析构函数 ,输出结果如下:

0x7ffe9d1edd0f construct

0x7ffe9d1edd0f destruct

在g++中,加上-fno-elide-constructors选项关闭优化后,输出结果如下:

0x7ffc46947d4f construct  // 在函数GetA中,调用无参构造函数A()构造出一个临时变量temp

0x7ffc46947d7f copy construct // 函数GetA return语句处,把临时变量temp做为参数传入并调用拷贝构造函数A(const A& cp)将返回值ret构造出来

0x7ffc46947d4f destruct // 函数GetA执行完return语句后,临时变量temp生命周期结束,调用其析构函数~A()

0x7ffc46947d7e copy construct // 函数GetA调用结束,返回上层main函数后,把返回值变量ret做为参数传入并调用拷贝构造函数A(const A& cp)将变量A a构造出来

0x7ffc46947d7f destruct // A a = GetA()语句结束后,返回值ret生命周期结束,调用其析构函数~A()

0x7ffc46947d7e destruct // A a要离开作用域,生命周期结束,调用其析构函数~A()

注:临时变量temp、返回值ret均为匿名变量

下面用c++代码模拟一下其优化行为:

  1. #include <new>
  2. A& GetA(void* p)
  3. {
  4. //由于p的内存是从外部传入的,函数返回后仍然有效,因此返回值可为A&
  5. //vs中,以下代码还可以写成:
  6. // A& o = *((A*)p);
  7. // o.A::A();
  8. // return o;
  9. return *new (p) A(); // placement new
  10. }
  11.  
  12. int main()
  13. {
  14. {
  15. char buf[sizeof(A)];
  16. A& a = GetA(buf);
  17. a.~A();
  18. }
  19.  
  20. return 0;
  21. }

NRVO

g++编译器、vs2005+ Release(开启/O2及以上优化开关)

修改上述代码,将GetA的实现修改成:

  1. A GetA()
  2. {
  3. A o;
  4. return o;
  5. }

在g++、vs2005+ Release中,上述代码也仅仅只会调用一次构造函数和析构函数 ,输出结果如下:

0x7ffe9d1edd0f construct

0x7ffe9d1edd0f destruct

g++加上-fno-elide-constructors选项关闭优化后,和上述结果一样

0x7ffc46947d4f construct

0x7ffc46947d7f copy construct

0x7ffc46947d4f destruct

0x7ffc46947d7e copy construct

0x7ffc46947d7f destruct

0x7ffc46947d7e destruct

但在vc6、vs2005以下、vs2005+ Debug中,没有进行NRVO优化,输出结果为:

18fec4 construct  // 在函数GetA中,调用无参构造函数A()构造出一个临时变量o

18ff44 copy construct  // 函数GetA return语句处,把临时变量o做为参数传入并调用拷贝构造函数A(const A& cp)将返回值ret构造出来

18fec4 destruct  // 函数GetA执行完return语句后,临时变量o生命周期结束,调用其析构函数~A()

18ff44 destruct // A a要离开作用域,生命周期结束,调用其析构函数~A()

下面用c++代码模拟一下vc6、vs2005以下、vs2005+ Debug上的行为:

  1. #include <new>
  2. A& GetA(void* p)
  3. {
  4. A o;
  5. //由于p的内存是从外部传入的,函数返回后仍然有效,因此返回值可为A&
  6. //vs中,以下代码还可以写成:
  7. // A& t = *((A*)p);
  8. // t.A::A(o);
  9. // return t;
  10. return *new (p) A(o); // placement new
  11. }
  12.  
  13. int main()
  14. {
  15. {
  16. char buf[sizeof(A)];
  17. A& a = GetA(buf);
  18. a.~A();
  19. }
  20.  
  21. return 0;
  22. }

注:与g++、vs2005+ Release相比,vc6、vs2005以下、vs2005+ Debug只优化掉了返回值到变量a的拷贝,命名局部变量o没有被优化掉,所以最后一共有2次构造和析构的调用

复制省略

典型情况是:调用构造函数进行值类型传参

  1. void Func(A a)
  2. {
  3. }
  4.  
  5. int main()
  6. {
  7. {
  8. Func(A());
  9. }
  10.  
  11. return 0;
  12. }

在g++和vc6、vs中,上述代码仅仅只会调用一次构造函数和析构函数 ,输出结果如下:

0x7ffeb5148d0f construct

0x7ffeb5148d0f destruct

在g++中,加上-fno-elide-constructors选项关闭优化后,输出结果如下:

0x7ffc53c141ef construct   // 在main函数中,调用无参构造函数构造实参变量o

0x7ffc53c141ee copy construct // 调用Func函数后,将实参变量o做为参数传入并调用拷贝构造函数A(const A& cp)将形参变量a构造出来

0x7ffc53c141ee destruct // 函数Func执行完后,形参变量a生命周期结束,调用其析构函数~A()

0x7ffc53c141ef destruct // 返回main函数后,实参变量o要离开作用域,生命周期结束,调用其析构函数~A()

下面用c++代码模拟一下其优化行为:

  1. void Func(const A& a)
  2. {
  3. }
  4.  
  5. int main()
  6. {
  7. {
  8. Func(A());
  9. }
  10.  
  11. return 0;
  12. }

优化失效的情况

开启g++优化,得到以下各种失效情况的输出结果:

(1)根据不同的条件分支,返回不同变量

  1. A GetA(bool bflag)
  2. {
  3. A a1, a2;
  4. if (bflag)
  5. return a1;
  6. return a2;
  7. }
  8.  
  9. int main()
  10. {
  11. A a = GetA(true);
  12.  
  13. return 0;
  14. }

0x7ffc3cca324f construct

0x7ffc3cca324e construct

0x7ffc3cca327f copy construct

0x7ffc3cca324e destruct

0x7ffc3cca324f destruct

0x7ffc3cca327f destruct

注1:2次缺省构造函数调用:用于构造a1、a2

注2:1次拷贝构造函数调用:用于拷贝构造返回值

注3:这儿仍然用右值引用优化掉了一次拷贝函数调用:返回值赋值给a

(2)返回参数变量

(3)返回全局变量

(4)返回复合数据类型中的成员变量

(5)返回值赋值给已构造好的变量(此时会调用operator==赋值运算符)

以上就是详解C++编译器优化技术的详细内容,更多关于C++编译器优化技术的资料请关注w3xue其它相关文章!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号