日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

《C++代码设计与重用》——2.5 浅拷贝和深拷贝

發(fā)布時(shí)間:2025/5/22 219 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《C++代码设计与重用》——2.5 浅拷贝和深拷贝 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本節(jié)書(shū)摘來(lái)自異步社區(qū)出版社《Imperfect C++中文版》一書(shū)中的第2章,第2.5節(jié),作者: 【美】Martin D.Carroll , Margaret A.Ellis,更多章節(jié)內(nèi)容可以訪問(wèn)云棲社區(qū)“異步社區(qū)”公眾號(hào)查看。

2.5 淺拷貝和深拷貝

C++代碼設(shè)計(jì)與重用
2.5 淺拷貝和深拷貝
有兩個(gè)操作,盡管它們具有某些不合乎需要的特性,但因?yàn)樗鼈兊氖褂梅秶軓V,進(jìn)而博得一定的注意,所以這兩個(gè)操作在這里有必要特別提及一下,這兩個(gè)操作就是淺拷貝操作和深拷貝操作。x對(duì)象的淺拷貝是指:另一個(gè)和x相同類(lèi)型的,并且它的數(shù)據(jù)成員和x相對(duì)應(yīng)的數(shù)據(jù)成員具有相同值的對(duì)象。x對(duì)象的深拷貝是指:另一個(gè)和x類(lèi)型相同的對(duì)象,它具有x直接或間接指向的對(duì)象的一份拷貝,并且在拷貝里,所有共享和循環(huán)的聯(lián)系依舊保留。考慮下面3個(gè)類(lèi):

class Z {//沒(méi)有數(shù)據(jù)成員//... }; class Y { private::Z* z;//沒(méi)有其他數(shù)據(jù)成員//... }; class x { private:int iY* y1;Y* y2;//沒(méi)有其他數(shù)據(jù)成員//... };

在圖2.1中,x2是X類(lèi)型對(duì)象x1的淺拷貝,x3是x1的深拷貝。

但是,對(duì)一個(gè)設(shè)計(jì)得很好,并且正確實(shí)現(xiàn)的程序庫(kù)(幾乎沒(méi)有異常產(chǎn)生),它的用戶應(yīng)該可以請(qǐng)求創(chuàng)建某個(gè)對(duì)象的拷貝—通過(guò)拷貝構(gòu)造函數(shù)—并且由程序庫(kù)適當(dāng)實(shí)現(xiàn)某種對(duì)象類(lèi)型的拷貝。除了一些特殊的類(lèi)之外,用戶是不需要了解拷貝函數(shù)的實(shí)現(xiàn)機(jī)制的,也不應(yīng)該指定用某種特殊的方式來(lái)拷貝一個(gè)對(duì)象。

讓我們還是回到討論的話題,對(duì)一個(gè)給定的類(lèi),我們很少用淺拷貝操作或深拷貝操作來(lái)實(shí)現(xiàn)它的拷貝構(gòu)造函數(shù)。假設(shè)我們用下面代碼來(lái)實(shí)現(xiàn)2.1節(jié)中的Rational類(lèi):

class Rational { private:Rational_rep* rep;//...};class Rational_rep {private:int num;int denom;//...};

在這里,我們只是簡(jiǎn)單地把成員變量num和denom移到一個(gè)單獨(dú)的類(lèi)里面。(我們將在8.2.4節(jié)看到,這種實(shí)現(xiàn)方法為類(lèi)Rational的用戶提供了鏈接兼容性。)下面是類(lèi)Rational和類(lèi)Rational_rep用深拷貝來(lái)實(shí)現(xiàn)的拷貝構(gòu)造函數(shù):

class Rational {public:Rational(const Rational& r) {Rep = new Rational_rep(*r.rep);}//...};class Rational_rep {public:Rational_rep(Rational_rep& rep) :num(rep.num),denom(rep.denom) {}//...);

當(dāng)用淺拷貝或者深拷貝來(lái)正確實(shí)現(xiàn)拷貝構(gòu)造函數(shù)的時(shí)候,我們應(yīng)該理所當(dāng)然地類(lèi)似(淺拷貝還有很大區(qū)別)上面那樣來(lái)實(shí)現(xiàn)這個(gè)構(gòu)造函數(shù)。但是,上面代碼之所以可以實(shí)現(xiàn),也僅僅是某種巧合;我們并不向用戶建議這種巧合。如果類(lèi)的實(shí)現(xiàn)改變了,那么拷貝構(gòu)造函數(shù)就可能不再實(shí)現(xiàn)淺拷貝或者深拷貝了。實(shí)際上,用戶也不應(yīng)該委托拷貝構(gòu)造函數(shù)實(shí)現(xiàn)這兩種拷貝。此外,這種(巧合)現(xiàn)象—指通過(guò)淺拷貝或者深拷貝來(lái)實(shí)現(xiàn)類(lèi)的拷貝構(gòu)造函數(shù)—發(fā)生的概率要比程序員所認(rèn)為的少很多。因?yàn)閷?duì)大部分類(lèi)來(lái)說(shuō),淺拷貝和深拷貝都不能用來(lái)實(shí)現(xiàn)類(lèi)的拷貝構(gòu)造函數(shù);并且對(duì)一些特殊的類(lèi),淺拷貝和深拷貝往往帶有不適合需要的屬性:它們不能保持程序的不變性。例如,為了盡可能地共享類(lèi)Rational_rep,我們可以這樣來(lái)改變類(lèi)Rational的實(shí)現(xiàn):

Struct Rational_rep {int refcnt; //引用計(jì)數(shù)。//...};class Rational {public:Rational(const Rational& r) {red = r.rep;++rep->refcnt;}//...};

一般當(dāng)我們要共享某個(gè)對(duì)象的時(shí)候,我們必須增加引用計(jì)數(shù),用它來(lái)決定在什么時(shí)候可以刪除一個(gè)共享對(duì)象。對(duì)于任何使用類(lèi)Rational這個(gè)版本的程序,它的不變性是指類(lèi)Rational_rep里面的引用計(jì)數(shù)等于指向這個(gè)共享Rational_rep的類(lèi)Rational的數(shù)目。讀者容易看出,創(chuàng)建類(lèi)Rational的淺拷貝將會(huì)違背這個(gè)不變性。

類(lèi)Rational的問(wèn)題也并不局限于淺拷貝。考慮下面的轉(zhuǎn)型,它在Rational不為零的情況下返回真值。

class Rational {public:operator bool() const {return rep->num != 0;}//...};

假設(shè)用戶經(jīng)常調(diào)用這個(gè)函數(shù)。為了優(yōu)化這個(gè)函數(shù)的實(shí)現(xiàn),讓我們改變類(lèi)Rational的實(shí)現(xiàn),來(lái)使所有值為零的Rational對(duì)象都指向同一個(gè)Rational_rep對(duì)象:

class Rational {public:operator bool() const {return rep == rep_of_zero;}//...private:static Rational_rep* rep_of_zero;//...};

這個(gè)bool轉(zhuǎn)型函數(shù)避免了一個(gè)間接的調(diào)用(很顯然獲得了一些效率的優(yōu)化,但這僅僅是一個(gè)例子)。讀者容易核實(shí),創(chuàng)建一個(gè)值為零的Rational對(duì)象的深拷貝,將會(huì)破壞不變性,這里的不變性是指,所有值為零的Rational對(duì)象都指向同一個(gè)Rational_rep對(duì)象1。

如果淺拷貝或者深拷貝操作有可能破壞某個(gè)不變性定義的話,那么類(lèi)的實(shí)現(xiàn)者當(dāng)然可以通過(guò)插入代碼以恢復(fù)這個(gè)不變性,從而避免破壞。然而,保存不變性這個(gè)做法并沒(méi)有改變淺拷貝或深拷貝破壞不變性的這個(gè)事實(shí)。況且,在更加復(fù)雜的類(lèi)里面,淺拷貝或者深拷貝操作也照樣破壞不變性,并且這種破壞性是很難甚至不可能得到修復(fù)的(見(jiàn)練習(xí)2.5c)。

假設(shè)類(lèi)X的淺拷貝和深拷貝操作不會(huì)破壞任何不變性,那么類(lèi)X是否應(yīng)該提供這些操作呢?見(jiàn)下面例子:

class X {public:X* shallow_copy(); //應(yīng)該提供這個(gè)函數(shù)嗎?X* deep_copy(); //應(yīng)該提供這個(gè)函數(shù)嗎?//...};

當(dāng)然不應(yīng)該,除非X是那些非常特殊的類(lèi),并且允許用戶指定它的拷貝實(shí)現(xiàn)方式。另一方面,如果我們想改變類(lèi)X的實(shí)現(xiàn),又不得破壞不變性,并且提供淺拷貝和深拷貝操作,那么這種改變也是不可能實(shí)現(xiàn)的。因此,我們可以這樣認(rèn)為:類(lèi)一般不應(yīng)該提供淺拷貝和深拷貝操作(見(jiàn)練習(xí)2.5d)。

1譯注:由深拷貝的定義可知,如果執(zhí)行深拷貝操作,那么也將拷貝出一個(gè)新的Rational rep對(duì)象,這與要求只有同一個(gè)Rational rep對(duì)象矛盾。
本文僅用于學(xué)習(xí)和交流目的,不代表異步社區(qū)觀點(diǎn)。非商業(yè)轉(zhuǎn)載請(qǐng)注明作譯者、出處,并保留本文的原始鏈接。

總結(jié)

以上是生活随笔為你收集整理的《C++代码设计与重用》——2.5 浅拷贝和深拷贝的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。