收藏 分享(赏)

C++代码优化方法总结.doc

上传人:ysd1539 文档编号:4406570 上传时间:2018-12-27 格式:DOC 页数:10 大小:39KB
下载 相关 举报
C++代码优化方法总结.doc_第1页
第1页 / 共10页
C++代码优化方法总结.doc_第2页
第2页 / 共10页
C++代码优化方法总结.doc_第3页
第3页 / 共10页
C++代码优化方法总结.doc_第4页
第4页 / 共10页
C++代码优化方法总结.doc_第5页
第5页 / 共10页
点击查看更多>>
资源描述

1、优化是一个非常大的主题,本文并不是去深入探讨性能分析理论,算法的效率,况且我也没有这个能力。我只是想把一些可以简单的应用到你的 C+代码中的优化技术总结在这里,这样,当你遇到几种不同的编程策略的时候,就可以对每种策略的性能进行一个大概的估计。这也是本文的目的之所在。一. 优化之前在进行优化之前,我们首先应该做的是发现我们代码的瓶颈(bottleneck)在哪里。然而当你做这件事情的时候切忌从一个 debug-version 进行推断,因为 debug-version 中包含了许多额外的代码。一个 debug-version 可执行体要比 release-version 大出 40%。那些额外的

2、代码都是用来支持调试的,比如说符号的查找。大多数实现都为 debug-version 和 release-version 提供了不同的 operator new 以及库函数。而且,一个 release-version 的执行体可能已经通过多种途径进行了优化,包括不必要的临时对象的消除,循环展开,把对象移入寄存器,内联等等。另外,我们要把调试和优化区分开来,它们是在完成不同的任务。 debug-version 是用来追捕 bugs 以及检查程序是否有逻辑上的问题。release-version 则是用来做一些性能上的调整以及进行优化。下面就让我们来看看有哪些代码优化技术吧!二. 声明的放置程序中

3、变量和对象的声明放在什么位置将会对性能产生显著影响。同样,对 postfix 和prefix 运算符的选择也会影响性能。这一部分我们集中讨论四个问题:初始化 v.s 赋值,在程序确实要使用的地方放置声明,构造函数的初始化列表,prefix v.s postfix 运算符。(1) 请使用初始化而不是赋值在 C 语言中只允许在一个函数体的开头进行变量的声明,然而在 C+中声明可以出现在程序的任何位置。这样做的目的是希望把对象的声明拖延到确实要使用它的时候再进行。这样做可以有两个好处:1. 确保了对象在它被使用前不会被程序的其他部分恶意修改。如果对象在开头就被声明然而却在 20 行以后才被使用的话,

4、就不能做这样的保证。2. 使我们有机会通过用初始化取代赋值来达到性能的提升,从前声明只能放在开头,然而往往开始的时候我们还没有获得我们想要的值,因此初始化所带来的好处就无法被应用。但是现在我们可以在我们获得了想要的值的时候直接进行初始化,从而省去了一步。注意,或许对于基本类型来说,初始化和赋值之间可能不会有什么差异,但是对于用户定义的类型来说,二者就会带来显著的不同,因为赋值会多进行一次函数调用-operator =。因此当我们在赋值和初始化之间进行选择的话,初始化应该是我们的首选。2) 把声明放在合适的位置上在一些场合,通过移动声明到合适的位置所带来的性能提升应该引起我们足够的重视。例如:b

5、ool is_C_Needed(); void use()C c1;if (is_C_Needed() = false)return; /c1 was not needed /use c1 herereturn; 上面这段代码中对象 c1 即使在有可能不使用它的情况下也会被创建,这样我们就会为它付出不必要的花费,有可能你会说一个对象 c1 能浪费多少时间,但是如果是这种情况呢:C c11000;我想就不是说浪费就浪费了。但是我们可以通过移动声明 c1 的位置来改变这种情况:void use()if (is_C_Needed() = false)return; /c1 was not neede

6、d C c1; /moved from the blocks beginning/use c1 herereturn; 怎么样,程序的性能是不是已经得到很大的改善了呢?因此请仔细分析你的代码,把声明放在合适的位置上,它所带来的好处是你难以想象的。(3) 初始化列表我们都知道,初始化列表一般是用来初始化 const 或者 reference 数据成员。但是由于他自身的性质,我们可以通过使用初始化列表来实现性能的提升。我们先来看一段程序:class Personprivate:C c_1;C c_2;public:Person(const C当然构造函数我们也可以这样写:Person:Person

7、(const Cc_2 = c2;那么究竟二者会带来什么样的性能差异呢,要想搞清楚这个问题,我们首先要搞清楚二者是如何执行的,先来看初始化列表:数据成员的声明操作都是在构造函数执行之前就完成了,在构造函数中往往完成的只是赋值操作,然而初始化列表直接是在数据成员声明的时候就进行了初始化,因此它只执行了一次 copy constructor。再来看在构造函数中赋值的情况:首先,在构造函数执行前会通过 default constructor 创建数据成员,然后在构造函数中通过 operator =进行赋值。因此它就比初始化列表多进行了一次函数调用。性能差异就出来了。但是请注意,如果你的数据成员都是基

8、本类型的话,那么为了程序的可读性就不要使用初始化列表了,因为编译器对两者产生的汇编代码是相同的。(4) postfix VS prefix 运算符prefix 运算符+和比它的 postfix 版本效率更高,因为当 postfix 运算符被使用的时候,会需要一个临时对象来保存改变以前的值。对于基本类型,编译器会消除这一份额外的拷贝,但是对于用户定义类型,这似乎是不可能的。因此请你尽可能使用 prefix 运算符。三. 内联函数内联函数既能够去除函数调用所带来的效率负担又能够保留一般函数的优点。然而,内联函数并不是万能药,在一些情况下,它甚至能够降低程序的性能。因此在使用的时候应该慎重。1我们先

9、来看看内联函数给我们带来的好处:从一个用户的角度来看,内联函数看起来和普通函数一样,它可以有参数和返回值,也可以有自己的作用域,然而它却不会引入一般函数调用所带来的负担。另外,它可以比宏更安全更容易调试。当然有一点应该意识到,inline specifier 仅仅是对编译器的建议,编译器有权利忽略这个建议。那么编译器是如何决定函数内联与否呢?一般情况下关键性因素包括函数体的大小,是否有局部对象被声明,函数的复杂性等等。2那么如果一个函数被声明为 inline 但是却没有被内联将会发生什么呢?理论上,当编译器拒绝内联一个函数的时候,那个函数会像普通函数一样被对待,但是还会出现一些其他的问题。例如

10、下面这段代码:/ filename Time.h#include#includeusing namespace std;class Timepublic:inline void Show() for (int i = 0; iusing namespace std;class V public: virtual void show() const coutshow(); void g()V v;f(v, int main()g();return 0;如果整个程序出现在一个单独的编译单元中,编译器能够对 main()中的 g()进行内联替换。并且在 g()中 f()的调用也能够被内联处理。因为传

11、给 f()的参数的动态类型能够在编译期被知晓,因此编译器能够把对虚函数的调用静态化。但是不能保证每个编译器都这样做。然而,一些编译器确实能够利用在编译期获得参数的动态类型从而使得函数的调用在编译期间就确定了下来,避免了动态绑定的负担。5 Function objects VS function pointers用 function objects 取代 function pointers 的好处不仅仅局限在能够泛化和简单的维护性上。而且编译器能够对 function object 的函数调用进行内联处理,从而进一步的增强了性能六. 最后的求助迄今为止为大家展示的优化技术并没有在设计以及代码的可

12、读性上做出妥协。事实上,它们中的一些还提高了软件的稳固性和可维护性。但是在一些对时间和内存有严格限制的软件开发中,上面的技术可能还不够;有可能还需要一些会影响软件的可移植性和扩展性的技术。但是这些技术只能在所有其他的优化技术都被应用但是还不符合要求的情况下使用。1 关闭 RTTI 和异常处理支持当你导入纯 C 代码给 C+编译器的时候,你可能会发现有一些性能上的损失。这并不是语言或者编译器的错误,而是编译器作出的一些调整。如果你想获得和 C 编译器同样的性能,那么请关闭编译器对 RTTI 以及异常处理的支持。为什么会这样呢?因为为了支持 RTTI 和异常处理,C+编译器会插入额外的代码。这样就

13、增加了可执行体的大小,从而使得效率有所下降。当应用纯 C 代码的时候,那些额外的代码是不需要的,所以你可以通过关闭来避免它。2 内联汇编对时间要求苛刻的部分可以用本地汇编来重写。结果可能是速度上的显著提高。然而,这个方法不能想当然的就去实施,因为它将使得将来的修改非常的困难。维护代码的程序员可能对汇编并不了解。如果想要把软件运行于其他平台也需要重写汇编代码部分。另外,开发和测试汇编代码是一件辛苦的工作,它将花费更长的时间。3 直接和操作系统进行交互API 函数可以使你直接与操作系统进行交互。有时,直接执行一个系统命令可能会快许多。出于这个目的,你可以使用标准函数 system()。例如,在一个 dos/windows 系统下,你可以这样显示当前目录下的文件:#include using namespace std;int main()system(“dir“); /execute the “dir“ command

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 网络科技 > C/C++资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报