您好,登錄后才能下訂單哦!
所謂的自我賦值,指得就是一個(gè)對(duì)象賦值給自己的簡(jiǎn)單行為,但這種看起來人畜無害動(dòng)作,在某些情形下卻可能會(huì)使得你的代碼崩潰。
自我賦值的語句,就像這樣:
Widget w;
w = w;
很明顯,這是一段愚蠢的代碼。但既然我們提到自我賦值會(huì)引發(fā)問題,那我們先來澄清一下自我賦值的情況其實(shí)有時(shí)并不是那么顯而易見的,并不一定都像上述代碼那么愚蠢,它們還可能是這樣:
a[i] = a[j];
*px = *py;
class base { ... };
class derived : base { ... };
void f(derived *p, base &r);
以上代碼中,a[i] 和 a[j] 有可能是同一對(duì)象,兩個(gè)不同的指針 px 和 py 有可能指向同一對(duì)象,而基類引用 r 也完全有可能引用了指針 p 所指向的同一對(duì)象。它們這看起來,要比前面的代碼隱蔽多了。
下面來說說,為什么自我賦值會(huì)有危險(xiǎn)??紤]一個(gè)儲(chǔ)存了一張 Jpeg 圖片數(shù)據(jù)的類:
class Image
{
... ...
private:
Jpeg *p;
};
下面是 Image 類的 operator=() 的實(shí)現(xiàn)代碼,看起來合情合理:
Image &operator=(const Image &r)
{
delete p;
p = new Jpeg( *r.p );
return *p;
}
但,如果 r 跟調(diào)用對(duì)象是同一對(duì)象時(shí),那將意味著在執(zhí)行 delete p 之時(shí)就已經(jīng)將 r 的圖像數(shù)據(jù)刪除了,此時(shí)再去根據(jù)此數(shù)據(jù) new 一個(gè)新對(duì)象將會(huì)引發(fā)錯(cuò)誤。糾正這個(gè)錯(cuò)誤也不難,只要加個(gè)簡(jiǎn)單的判斷:
Image &operator=(const Image &r)
{
if( *this == r ) // 自我檢測(cè)
return;
delete p;
p = new Jpeg( *r.p );
return *p;
}
這的確解決了所謂 “自我賦值安全性” 問題,但隨之而來還有另一個(gè)問題,那就是 “異常安全性” 問題,假設(shè)程序在分配堆內(nèi)存時(shí),不巧發(fā)生了始料未及的錯(cuò)誤,也就是 new 語句發(fā)生了異常,此時(shí)因?yàn)?原先對(duì)象的圖像數(shù)據(jù) p 已經(jīng)被刪除,因此這個(gè)賦值運(yùn)算將會(huì)導(dǎo)致一個(gè)尷尬的結(jié)局:新的數(shù)據(jù)尚未被正常賦予,舊的數(shù)據(jù)已經(jīng)被匆匆刪除。
因此,我們還需要仔細(xì)打磨以上代碼,可以將之修改為:
Image &operator=(const Image &r)
{
Jpeg *tmp = this->p;
p = new Jpeg( *r.p );
delete tmp;
return *this;
}
此時(shí),如果 new 語句再次發(fā)生異常,將不會(huì)對(duì)任何數(shù)據(jù)造成影響,可以免除編寫 自我檢測(cè) 代碼。當(dāng)然,如果恰巧確實(shí)發(fā)生了 自我賦值 事件,那么代碼將會(huì)白白浪費(fèi)時(shí)間創(chuàng)建了一個(gè)原圖像的復(fù)制品,然后讓指針指向新的復(fù)制品上。如果你很在乎這個(gè)事情,你可以將 自我檢測(cè) 代碼重新加到代碼中,可是這又將增加程序的尺寸,引入了一個(gè)新的結(jié)構(gòu)分支,prefetching、caching 和 pipelining 指令的效率都會(huì)被拖累。因此你需要權(quán)衡這二者中的利弊。
總結(jié):
編寫 operator=() 函數(shù)時(shí)要格外注意操作數(shù)是否是同一對(duì)象。
需要格外注意會(huì)發(fā)生異常(尤其是堆內(nèi)存申請(qǐng)的代碼)的代碼處,是否會(huì)導(dǎo)致程序邏輯的不一致性。
保證任何函數(shù)在同時(shí)操作多個(gè)對(duì)象時(shí),哪怕有多個(gè)對(duì)象是同一對(duì)象的情況下也能正常執(zhí)行。
長(zhǎng)按以下二維碼進(jìn)入 微店●秘籍酷 獲取 IT 編程技術(shù)入門指導(dǎo)
微信原文:https://mp.weixin.qq.com/s?__biz=MzAxNzYzMTU0Ng==&mid=2651289247&idx=1&sn=8d50a35fb3b2fa57095ea8c3d0088afe&chksm=801146cab766cfdc52d2f2b4f6e76b59f92595263e13a67a3583bb03234aaea04f577ac50435#rd
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。