王朝网络
分享
 
 
 

Thinking again in C++(二)自赋值是非公断

王朝vc·作者佚名  2006-01-08
宽屏版  字体: |||超大  

爱死Thinking in系列了,所以起了这个名字。本文的思想也部分来至于这套书,或参照对比,或深入挖掘,或补益拾慧,或有感而发,既包括Thinking in C++,甚至也包括Thinking in Java。

Thinking again in C++(二)自赋值是非公断

关键字:C++,自赋值,自复制,赋值,assign,assignment,复制,拷贝,copy

1.需要考虑的自赋值。当类包含指针或引用成员时应注意检查。

class String

{

private:

char * pc_Buffer;

public:

String & operator=(const String & strR);

String & operator+=(const String & strR);

//...

};

(1)类内部:对称赋值运算符、接受自身类型或自身基类类型参数的成员函数,有时候还要考虑+=系列运算符。

String & String::operator=(const String & strR)

{

if (this==&strR) //[1]

return *this;

delete [] pc_Buffer; //[2]

pc_Buffer=new char[strlen(strR.pc_Buffer)+1];//[3]

//...

}

[1]中的判断是必须的。如果this==&strR,[2]将本身删除,[3]就会使用“悬挂指针”。

下面operator+=()的实现隐藏着错误。

String & String::operator+=(const String & strR)

{

int iLengthNew=strlen(pc_Buffer)+strlen(strR.pc_Buffer);

char * pcBufferNew=new char[iLengthNew+1];

strcpy(pcBufferNew,pc_Buffer);

delete [] pc_Buffer; //[4]

strcat(pcBufferNew,strR.pc_Buffer); //[5]

pc_Buffer=pcBufferNew;

return *this;

}

如果this==&strR,[4]将本身删除,[5]就会使用“悬挂指针”。正确的做法不必使用判断语句,只需调换[4][5]两条语句的顺序。

(2)类外部(包括友元):接受多个同一类型参数或多个有继承关系的类型参数的函数。

class CDerive : public CBase{};

void f(CBase & b1,CBase & b2);

void g(CBase & b,CDerive & d);

CBase bSame;

CDerive dSame;

f(bSame,bSame); //[1]

f(dSame,dSame); //[2]

g(dSame,dSame); //[3]

[1][2][3]都出现了自赋值,所以f()、g()的设计中都要有所考虑。

2.不可能出现自赋值。

(1)拷贝构造器:因为正在构造的对象还未完全生成,而传递给构造器的实参对象是已构造完毕的对象,这两者绝不可能是同一对象。

(2)非对称赋值运算符:即使形参类型是自身的基类。若D是B的派生类,无论是否重载了对称赋值运算符,D类对象之间的赋值行为都不会调用D::operator=(const B & b)。

class CDerive : public CBase

{

public:

operator=(const CBase & b); //不用考虑this和b之间的自赋值

void f(const CBase & b); //需要考虑this和b之间的自赋值

};

CDerive dSame;

dSame=dSame; //[1]

dSame.f(dSame); //[2]

语句[1]中,编译器不会把dSame上溯造型为CBase,而是调用缺省或自定义的D::operator=(const D & d)。只有等式左边确为D,右边确为B,才调用D::operator=(const B & b),这时不可能出现自赋值。相反,语句[2]中,编译器会把dSame上溯造型为CBase,所以f()需要考虑自赋值。

3.不是自赋值的赋值。仅仅内容相同的赋值不是自赋值。

CTest a,b,same;

a=same;

b=same;

a=b; //[1]

[1]不是自赋值,不会出问题,不需要检查,而且内容相同无法直接用地址来检查。

4.不应该检查的自赋值。

strcpy(char * strDest,const char * strSrc);中,当strDest==strSrc时,是自赋值,但并不会出错。

发现自赋值直接返回,这种特定情况下,也许能提高函数效率10倍,但绝大多数没有出现自赋值时都多了一个条件判断,可能降低函数效率10%,最后综合计算加权平均效率可能还是降低了。这取决于自赋值出现的概率。

设不判断自赋值,函数执行时间为1;若检查自赋值,设出现自赋值的概率为x,直接返回函数执行时间为0.1,不出现自赋值,多了一个条件判断函数执行时间为1.1,那么如果要求加权平均效率不降低:

0.1x+1.1(1-x)<1

解之,得:x>0.1。也就是说自赋值出现的概率必须大于10%,这在实际代码中可能吗?

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
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- 王朝网络 版权所有