溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

關(guān)于對(duì)象的自我賦值行為

發(fā)布時(shí)間:2020-07-26 02:36:42 來源:網(wǎng)絡(luò) 閱讀:1585 作者:林世霖 欄目:編程語言

關(guān)于對(duì)象的自我賦值行為 

所謂的自我賦值,指得就是一個(gè)對(duì)象賦值給自己的簡(jiǎn)單行為,但這種看起來人畜無害動(dòng)作,在某些情形下卻可能會(huì)使得你的代碼崩潰。


關(guān)于對(duì)象的自我賦值行為


自我賦值的語句,就像這樣:


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ì)象。它們這看起來,要比前面的代碼隱蔽多了。

關(guān)于對(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)衡這二者中的利弊。

關(guān)于對(duì)象的自我賦值行為

總結(jié):

  1. 編寫 operator=() 函數(shù)時(shí)要格外注意操作數(shù)是否是同一對(duì)象。

  2. 需要格外注意會(huì)發(fā)生異常(尤其是堆內(nèi)存申請(qǐng)的代碼)的代碼處,是否會(huì)導(dǎo)致程序邏輯的不一致性。

  3. 保證任何函數(shù)在同時(shí)操作多個(gè)對(duì)象時(shí),哪怕有多個(gè)對(duì)象是同一對(duì)象的情況下也能正常執(zhí)行。

     

長(zhǎng)按以下二維碼進(jìn)入 微店秘籍酷 獲取 IT 編程技術(shù)入門指導(dǎo)

關(guān)于對(duì)象的自我賦值行為

微信原文:https://mp.weixin.qq.com/s?__biz=MzAxNzYzMTU0Ng==&mid=2651289247&idx=1&sn=8d50a35fb3b2fa57095ea8c3d0088afe&chksm=801146cab766cfdc52d2f2b4f6e76b59f92595263e13a67a3583bb03234aaea04f577ac50435#rd 


向AI問一下細(xì)節(jié)

免責(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)容。

AI