分享
 
 
 

C++ 代码优化(五)

王朝c/c++·作者佚名  2006-01-06
窄屏简体版  字體: |||超大  

提出公共子表达式

在某些情况下,C++编译器不能从浮点表达式中提出公共的子表达式,因为这意味着相当于对表达式重新排序。需要特别指出的是,编译器在提取公共子表达式前不能按照代数的等价关系重新安排表达式。这时,程序员要手动地提出公共的子表达式(在VC.net里有一项“全局优化”选项可以完成此工作,但效果就不得而知了)。

推荐的代码

float a, b, c, d, e, f;

...

e = b * c / d;

f = b / d * a;

float a, b, c, d, e, f;

...

const float t(b / d);

e = c * t;

f = a * t;  

推荐的代码

float a, b, c, e, f;

...

e = a / c;

f = b / c;

float a, b, c, e, f;

...

const float t(1.0f / c);

e = a * t;

f = b * t;  

结构体成员的布局

很多编译器有“使结构体字,双字或四字对齐”的选项。但是,还是需要改善结构体成员的对齐,有些编译器可能分配给结构体成员空间的顺序与他们声明的不同。但是,有些编译器并不提供这些功能,或者效果不好。所以,要在付出最少代价的情况下实现最好的结构体和结构体成员对齐,建议采取这些方法:

按类型长度排序

把结构体的成员按照它们的类型长度排序,声明成员时把长的类型放在短的前面。

把结构体填充成最长类型长度的整倍数

把结构体填充成最长类型长度的整倍数。照这样,如果结构体的第一个成员对齐了,所有整个结构体自然也就对齐了。下面的例子演示了如何对结构体成员进行重新排序:

不好的代码,普通顺序 推荐的代码,新的顺序并手动填充了几个字节

struct

{

char a[5];

long k;

double x;

} baz;

struct

{

double x;

long k;

char a[5];

char pad[7];

} baz;  

这个规则同样适用于类的成员的布局。

按数据类型的长度排序本地变量

当编译器分配给本地变量空间时,它们的顺序和它们在源代码中声明的顺序一样,和上一条规则一样,应该把长的变量放在短的变量前面。如果第一个变量对齐了,其它变量就会连续的存放,而且不用填充字节自然就会对齐。有些编译器在分配变量时不会自动改变变量顺序,有些编译器不能产生4字节对齐的栈,所以4字节可能不对齐。下面这个例子演示了本地变量声明的重新排序:

不好的代码,普通顺序 推荐的代码,改进的顺序

short ga, gu, gi;

long foo, bar;

double x, y, z[3];

char a, b;

float baz;

double z[3];

double x, y;

long foo, bar;

float baz;

short ga, gu, gi;  

避免不必要的整数除法

整数除法是整数运算中最慢的,所以应该尽可能避免。一种可能减少整数除法的地方是连除,这里除法可以由乘法代替。这个替换的副作用是有可能在算乘积时会溢出,所以只能在一定范围的除法中使用。

不好的代码 推荐的代码

int i, j, k, m;

m = i / j / k;

int i, j, k, m;

m = i / (j * k);

把频繁使用的指针型参数拷贝到本地变量

避免在函数中频繁使用指针型参数指向的值。因为编译器不知道指针之间是否存在冲突,所以指针型参数往往不能被编译器优化。这样是数据不能被存放在寄存器中,而且明显地占用了内存带宽。注意,很多编译器有“假设不冲突”优化开关(在VC里必须手动添加编译器命令行/Oa或/Ow),这允许编译器假设两个不同的指针总是有不同的内容,这样就不用把指针型参数保存到本地变量。否则,请在函数一开始把指针指向的数据保存到本地变量。如果需要的话,在函数结束前拷贝回去。 不好的代码 推荐的代码

?/ 假设 q != r

void isqrt(unsigned long a, unsigned long* q, unsigned long* r)

{

*q = a;

if (a >; 0)

{

while (*q >; (*r = a / *q))

{

*q = (*q + *r) >;>; 1;

}

}

*r = a - *q * *q;

}

// 假设 q != r

void isqrt(unsigned long a, unsigned long* q, unsigned long* r)

{

unsigned long qq, rr;

qq = a;

if (a >; 0)

{

while (qq >; (rr = a / qq))

{

qq = (qq + rr) >;>; 1;

}

}

rr = a - qq * qq;

*q = qq;

*r = rr;

}

赋值与初始化

先看看以下代码:

class CInt

{

int m_i;

public:

CInt(int a = 0):m_i(a) { cout <;<; ";CInt"; <;<; endl; }

~CInt() { cout <;<; ";~CInt"; <;<; endl; }

CInt operator + (const CInt&; a) { return CInt(m_i + a.GetInt()); }

void SetInt(const int i){ m_i = i; }

int GetInt() const{ return m_i; }

};

不好的代码 推荐的代码

void main()

{

CInt a, b, c;

a.SetInt(1);

b.SetInt(2);

c = a + b;

}

void main()

{

CInt a(1), b(2);

CInt c(a + b);

}  

这两段代码所作的事都一样,但那一个更好呢?看看输出结果就会发现,不好的代码输出了四个";CInt";和四个";~CInt";,而推荐的代码只输出三个。也就是说,第二个例子比第一个例子少生成一次临时对象。Why? 请注意,第一个中的c用的是先声明再赋值的方法,第二个用的是初始化的方法,它们有本质的区别。第一个例子的";c = a + b";先生成一个临时对象用来保存a + b的值,再把该临时对象用位拷贝的方法给c赋值,然后临时对象被销毁。这个临时对象就是那个多出来的对象。第二个例子直接用拷贝构造函数的方法对c初始化,不产生临时对象。所以,尽量在需要使用一个对象时才声明,并用初始化的方法赋初值。

尽量使用成员初始化列表

在初始化类的成员时,尽量使用成员初始化列表而不是传统的赋值方式。

不好的代码 推荐的代码

籧lass CMyClass

{

string strName;

public:

CMyClass(const string&; str);

};

CMyClass::CMyClass(const string&; str)

{

strName = str;

}

class CMyClass

{

string strName;

int i;

public:

CMyClass(const string&; str);

};

CMyClass::CMyClass(const string&;str)

: strName(str)

{

}  

不好的例子用的是赋值的方式。这样,strName会先被建立(调用了string的默认构造函数),再由参数str赋值。而推荐的例子用的是成员初始化列表,strName直接构造为str,少调用一次默认构造函数,还少了一些安全隐患。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有