條款13 以對(duì)象管理資源
- C++程序中最常使用的資源就是動(dòng)態(tài)分配內(nèi)存,并且還包括文件描述器蚌父,互斥鎖哮兰,GDI對(duì)象毛萌、數(shù)據(jù)庫(kù)連接、網(wǎng)絡(luò)socket等喝滞。不管哪一種資源阁将,當(dāng)不再使用的時(shí)候必須將其歸還給系統(tǒng)。
- 考慮以下Fun函數(shù)右遭,若動(dòng)態(tài)分配內(nèi)存后做盅,不小心使用了return、goto窘哈、或者發(fā)生了異常吹榴,就有可能導(dǎo)致分配的內(nèi)存不會(huì)被釋放。當(dāng)然滚婉,謹(jǐn)慎的編寫程序可以避免上述錯(cuò)誤图筹,但是必須考慮到,代碼可能在時(shí)間漸漸過(guò)去后被修改让腹,一旦軟件開始接受維護(hù)婿斥,可能會(huì)被添加欠缺考慮的return等語(yǔ)句而導(dǎo)致delete不能被正常執(zhí)行。為了確保資源被正確釋放哨鸭,正確的做法可以是將資源放入一個(gè)對(duì)象內(nèi)民宿,并讓該對(duì)象的析構(gòu)函數(shù)會(huì)自動(dòng)釋放那些資源(注意條款08 別讓異常逃出析構(gòu)函數(shù))。
void Fun()
{
int* pBuff = new int(10);
... //干點(diǎn)別的事情
delete pBuff;
}
- 利用智能指針可以方便的實(shí)現(xiàn)利用對(duì)象來(lái)管理動(dòng)態(tài)內(nèi)存資源像鸡。經(jīng)過(guò)測(cè)試活鹰,當(dāng)需要考慮效率的時(shí)候,不如將資源放入一個(gè)簡(jiǎn)單的自定義類中進(jìn)行管理(構(gòu)造函數(shù)中獲取資源只估,析構(gòu)函數(shù)中釋放資源)志群。
條款14 在資源類中小心coping行為
- 禁止復(fù)制。如同類unique_ptr那樣蛔钙,比如一個(gè)資源類包含了互斥鎖锌云,那么這個(gè)類就應(yīng)該禁止復(fù)制。通過(guò)將一系列的拷貝操作聲明為private并且不進(jìn)行定義來(lái)實(shí)現(xiàn)禁止復(fù)制吁脱。
- 引用計(jì)數(shù)法桑涎。如同類shared_ptr那樣,將一直有資源兼贡,直到它的最后一個(gè)使用者被銷毀攻冷。實(shí)際上使用shared_ptr類并傳入自己的刪除器可以很方便的實(shí)現(xiàn)對(duì)資源進(jìn)行引用計(jì)數(shù)法管理。
- 復(fù)制底部資源遍希。有時(shí)候需要針對(duì)一份資源等曼,需要擁有其任意數(shù)量的副本,此時(shí)進(jìn)行對(duì)資源的深拷貝。
- 轉(zhuǎn)移底部資源禁谦。將資源從一個(gè)擁有者轉(zhuǎn)移給另一個(gè)擁有者胁黑。即移動(dòng)的概念。當(dāng)對(duì)unique_ptr進(jìn)行std::move的時(shí)候就是這種情況州泊。
條款15 在資源類中提供對(duì)原始資源的直接訪問(wèn)
- 存在很多函數(shù)需要訪問(wèn)原始資源别厘,所以每個(gè)資源類都應(yīng)該提供對(duì)原始資源直接訪問(wèn)的方法,可以是顯示轉(zhuǎn)換(比如C++智能指針的get())拥诡,也可以使用隱式轉(zhuǎn)換
- C++智能指針對(duì)->和*進(jìn)行了重載,它們?cè)试S隱式轉(zhuǎn)換至底部原始指針氮发。
unique_ptr<string> pStr(new string("szn"));
const auto nSizeC = pStr->size(); //nSizeC = 3
條款16:成對(duì)使用new和delete時(shí)要采取相同的形式渴肉。
- 使用new[]分配內(nèi)存的時(shí)候,會(huì)有多個(gè)構(gòu)造函數(shù)被調(diào)用爽冕,當(dāng)不慎使用delete刪除new[]分配的內(nèi)存時(shí)仇祭,對(duì)應(yīng)的析構(gòu)函數(shù)的調(diào)用次數(shù)會(huì)出錯(cuò)。
- 當(dāng)使用typedef的時(shí)候特別要小心:
typedef int Int10[10];
int* pTem = new Int10;
delete[] pTem;
條款17 以獨(dú)立的語(yǔ)句將new出來(lái)的對(duì)象放入智能指針中
- 考慮如下語(yǔ)句:
Fun0(shared_ptr<int>(new int), Fun1());
由于函數(shù)形參的調(diào)用時(shí)機(jī)不同颈畸,上述函數(shù)的調(diào)用方式可能是這樣的:首先執(zhí)行new int乌奇,然后執(zhí)行Fun1(),最后執(zhí)行shared_ptr的構(gòu)造函數(shù)眯娱,當(dāng)在Fun1()中產(chǎn)生異常礁苗,則將導(dǎo)致內(nèi)存泄露。
避免上述問(wèn)題的方法很簡(jiǎn)單:
shared_ptr<int> pInt(new int);
Fun0(pInt, Fun1());
條款18 讓接口容易被正確使用徙缴,不易被誤用
- 如果客戶企圖使用某個(gè)接口而卻沒(méi)有獲得他所預(yù)期的行為试伙,那么這個(gè)代碼就不該通過(guò)編譯。
- 促進(jìn)正確使用的方法包括接口的一致性于样,以及與內(nèi)置類型的行為兼容疏叨。
- 阻止誤用的方法包括建立新類型、限制類型上的操作穿剖,束縛對(duì)象值蚤蔓,以及消除客戶的資源管理責(zé)任。
條款20 pass by reference to const 替換 pass by value
- C++的底層操作會(huì)將傳引用操作以指針的形式來(lái)實(shí)現(xiàn)糊余。
- 傳遞const的引用可以避免父對(duì)象接收子對(duì)象時(shí)候面臨的子對(duì)象被切割的問(wèn)題秀又。
- 傳遞const的引用可以有效避免無(wú)謂的拷貝和銷毀操作,在性能上產(chǎn)生優(yōu)勢(shì)
- 對(duì)于內(nèi)置類型以及STL的迭代器以及函數(shù)對(duì)象,對(duì)它們而言傳遞值比傳遞引用往往更加適當(dāng)贬芥。
條款21 必須返回對(duì)象時(shí)涮坐,別妄想返回引用
- 絕不要返回指向一個(gè)存在于棧中的對(duì)象的指針或引用,或返回一個(gè)存在于堆的對(duì)象的引用(需自己管理資源)誓军,亦或是返回一個(gè)指向在棧中聲明并定義的static對(duì)象的引用袱讹。當(dāng)必須返回對(duì)象的時(shí)候,老實(shí)的創(chuàng)建一個(gè)對(duì)象返回就好了。至于是不是必須要返回對(duì)象捷雕,要想想是否有其他可能來(lái)避免返回一個(gè)對(duì)象(傳參進(jìn)去嘍)
條款22 將成員變量聲明為private
- 將成員變量聲明為private的椒丧,這可以賦予客戶訪問(wèn)數(shù)據(jù)的一致性、可細(xì)微劃分訪問(wèn)控制救巷、允諾約束條件獲得保證壶熏,并讓類的設(shè)計(jì)者以充分的實(shí)現(xiàn)彈性。
- 切記protected并不比public更具封裝性浦译。若子類以public方式繼承棒假,則可以通過(guò)using輕松改變父類中protected成員的訪問(wèn)權(quán)限。而且在派生類中精盅,派生類也可以直接使用protected變量帽哑,這也給基類的封裝性帶來(lái)巨大的打擊
- 即使擁有類的源碼,改變?nèi)魏蝡ublic事物的能力仍極端受束縛叹俏,因?yàn)闀?huì)破壞太多客戶代碼妻枕。public意味著不封裝,即意味著不可改變
條款23 以非成員函數(shù)粘驰、非友元函數(shù)替換成員函數(shù)
- 越少的代碼可以訪問(wèn)到類的私有成員數(shù)據(jù)屡谐,那么類的封裝性就越好
- 如果一個(gè)類包含很多可復(fù)用的工具函數(shù),考慮下這些函數(shù)是不是非要定義為類的成員函數(shù)蝌数。一個(gè)將數(shù)據(jù)以及操作數(shù)據(jù)的函數(shù)捆綁在一起組成一個(gè)classEverything的類愕掏,其實(shí)不是一個(gè)很好的習(xí)慣。在C++中較自然的做法是將一個(gè)類以及此類的輔助函數(shù)放在一個(gè)命名空間中顶伞,而不是讓這些輔助函數(shù)定義為類的成員函數(shù)
條款24 若所有參數(shù)都可能需要類型轉(zhuǎn)換亭珍,那么最好將其聲明為類的非成員函數(shù)
- 經(jīng)典的例子是類的operator *(...)等算術(shù)操作
條款25 考慮為類寫出一個(gè)不拋出異常的swap函數(shù)
- swap是一個(gè)有趣的函數(shù),原本是STL的一部分枝哄,而后來(lái)成為異常安全性變成的脊柱肄梨,以及用來(lái)處理自我賦值的可能性。
- 當(dāng)std::swap對(duì)自定義的類型效率不高的時(shí)候(比如在這個(gè)類型中使用了指針指向了一個(gè)內(nèi)存挠锥,如此swap應(yīng)該交換指針而非交換指針?biāo)笇?duì)象)众羡,提供一個(gè)swap成員函數(shù),并確定這個(gè)函數(shù)不拋出異常
- 如果提供一個(gè)成員函數(shù)swap蓖租,那么也該提供一個(gè)非成員函數(shù)版本的swap來(lái)調(diào)用成員函數(shù)版本的swap粱侣。
- 不要試圖往std命名空間中添加新的成員,這種行為是未定義的蓖宦。但是對(duì)于std命名空間中的模板進(jìn)行特例化也是挺好的
- 本章建議再看原書齐婴,這里只是簡(jiǎn)單的歸納了下
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者