转自:http://blog.sina.com.cn/s/blog_40965d3a0101eajf.html
(1)用移位实现整数的乘除法运算,浮点数不适合
a *= 4;
b /= 4;
c *= 9;
d *= 7;
可以修改为:
a <<= 2;
b >>= 2;(b必须为无符号的)
c = (c << 3) + c;
d = (d << 3) - d;
(2)优化循环,提高效率
a.在多重循环中,CPU跨切循环层的次数会对循环的效率产生相对较大的影响,所以如果可能,应将次数最多的循环放在最内层,次数最少的循环放在最外层。
b.如果循环体内存在逻辑判断,并且循环次数很大,宜将逻辑判断移动循环体外。
c.如果类似于给数组赋值,循环的次数并不多,不用循环,直接手写赋值语句反而更快。
(3)改造switch语句
a.对于case值,按照发生频率由高到低依此往下书写代码。
b.如果case标号很多,为了减少比较次数,应当把这样的switch语句转换为嵌套的switch语句。把发生频率高的case标号放在一个switch语句中,并且是嵌套switch语句的最外层。
(4)精简函数参数
函数在调用时会建立栈来存储所需的参数值,因此函数的调用负担会随着参数列表的增长而增加。并且,参数的个数会影响进栈出栈的次数,当参数很多的时候,这样的操作就会花费很长的时间。因此,精简函数参数,减少参数个数可以提高函数调用的效率。
如果参数实在是多,可以把参数封装进一个单独的结构体或类中,通过引用进行传递。
(5)谨慎使用内嵌汇编
a.开发和测试汇编代码是很辛苦的工作。
b.汇编语言的可读性较差,代码维护难度加大。
c.平台移植性差,很有可能需要根据平台重写汇编代码。
(6)努力减少内存碎片
首先,尽可能少地使用动态内存。在大多数情况下,可以使用静态或自动储存,或者用STL容器,减少对动态内存的依赖。
其次,尽量分配和重分配大块的内存,降低内存碎片发生的几率。例如,不要为一个单一的对象分配内存,而是一次分配一个对象数组。当然,我们也可以求助于自定义的内存池。
(7)正确使用内联函数
inline关键字只是告诉编译器最好使用内联方式来处理某个函数,但是编译器是否接受取决于以下关键性的因素:
a.函数体的大小
b.是否有局部对象被声明
c.函数的复杂性(是否存在函数调用、递归等)
(8)用初始化取代赋值
只有一点需要注意,就是对内置数据类型而言,初始化和赋值之间是没有差异的,因为内置类型没有构造和析构过程。
(9)尽可能地减少临时对象
如下代码:
string FindAddr(list<Employee> l, string name)
{
}
上面的代码中,一共有5处临时变量:
a.list<Employee> l
b.string name
c.i++
d.if (*i == name)
e.return “”
优化版本如下:
string FindAddr(const list<Employee>& l, const string& name)
{
}
(10)不成熟的优化时万恶之源
在进行代码优化之前,需要考虑以下几个问题:
a.算法是否正确?
对错误的程序做优化,太荒谬!
b.如何在代码优化和可读性之间进行选择?
根据需求而定,一般情况下,优先可读性。
c.该如何优化?
按照经典的“20-80”原则,代码执行时间的80%花费在20%的代码上,优先优化那些造成性能瓶颈的代码。可以借助编译器附带的代码分析工具(profiling)来完成。
d.如何选择优化方向?
优先优化算法,其次是数据结构,最后才是实现细节。