Effective C++學(xué)習(xí)筆記(第五章)

條款26:盡可能延后變量定義式的出現(xiàn)時(shí)間
  • 考察下面的示例代碼:
void Foo()
{
  std::string myStr;
  if (條件) {
    // 沒(méi)用用到myStr
    return;
  }
  // 使用myStr變量的代碼
}

很顯然延赌,這里的myStr提前定義了,并且會(huì)帶來(lái)額外的默認(rèn)構(gòu)造函數(shù)的開(kāi)銷(xiāo)叉橱,雖然在這個(gè)例子中微乎其微挫以。

  • 在定義一個(gè)類(lèi)對(duì)象時(shí),盡可能使用其帶參數(shù)的構(gòu)造函數(shù)窃祝,而不是先使用默認(rèn)構(gòu)造函數(shù)然后再使用賦值語(yǔ)句操作掐松。

  • 在for循環(huán)中用到的臨時(shí)變量最好是在循環(huán)體中定義,這樣做的好處是臨時(shí)變量的作用域只在循環(huán)體中粪小,避免了與外部變量的沖突甩栈。

for (int i = 0; i < N; i++) {
  MyClass obj;  // 在循環(huán)體內(nèi)定義變量,這是建議的做法糕再。
  // 循環(huán)體代碼
}
條款27:盡量少做轉(zhuǎn)型動(dòng)作

C++中新型的類(lèi)型轉(zhuǎn)換有:

  • const_cast:用于去掉const變量的const屬性量没,但是如果通過(guò)轉(zhuǎn)換后的非const指針去修改一個(gè)const變量是造成未定義的后果囱持。
const int val = 100;
int *p = const_cast<int*>(&val);
*p = 101; // undefined behavior

詳見(jiàn):https://en.cppreference.com/w/cpp/language/const_cast
PS:個(gè)人覺(jué)得const_cast有點(diǎn)讓人摸不著頭腦佳谦,不知道為啥要設(shè)計(jì)這個(gè)轉(zhuǎn)換。

  • dynamic_cast:“安全向下”轉(zhuǎn)型蜘欲,用于將一個(gè)基類(lèi)型指針轉(zhuǎn)換為子類(lèi)型指針,存在額外開(kāi)銷(xiāo)袭灯,并且需要判斷轉(zhuǎn)換后的結(jié)果是否為空刺下。
class B {
public:
    B() {}
    virtual ~B() {}
};

class D : public B {

};

int main()
{
    B* pb1 = new D();
    B* pb2 = new B();

    D* pd1 = dynamic_cast<D*>(pb1);
    if (pd1 != nullptr) {
        std::cout << "pd1 is ref to D obj" << std::endl;
    } else {
        std::cout << "pd1 is not ref to D obj" << std::endl;
    }

    D* pd2 = dynamic_cast<D*>(pb2);
    if (pd2 != nullptr) {
        std::cout << "pd2 is ref to D obj" << std::endl;
    } else {
        std::cout << "pd2 is not ref to D obj" << std::endl;
    }

    return 0;
}
  • reinterpret_cast:常用于重新解釋一個(gè)數(shù)據(jù)結(jié)構(gòu),存在比較大的安全風(fēng)險(xiǎn)稽荧。
  • statitc_cast:對(duì)應(yīng)于C語(yǔ)言的中強(qiáng)制轉(zhuǎn)換橘茉。

使用建議:

  • 盡可能使用C++新的轉(zhuǎn)型關(guān)鍵字
  • 如無(wú)必要,盡量減少轉(zhuǎn)型姨丈,特別是dynamic_cast這種轉(zhuǎn)換畅卓,影響性能。
條款28:避免返回handles指向?qū)ο髢?nèi)部成分
  • 一個(gè)類(lèi)中如果定義了private成員變量蟋恬,但同時(shí)又通過(guò)public成員函數(shù)返回了其指針或者引用翁潘,這樣就會(huì)間接的破壞了類(lèi)的封裝性,原本private成員變量會(huì)被外部客戶(hù)直接使用歼争。
  • 返回類(lèi)中成員變量的引用或者指針時(shí)拜马,會(huì)增加“懸垂指針”問(wèn)題的產(chǎn)生的風(fēng)險(xiǎn)。因?yàn)殂迦蓿?dāng)外部代碼獲取到這些引用或者指針后俩莽,其對(duì)應(yīng)的類(lèi)實(shí)例對(duì)象可能在其它地方已經(jīng)釋放了。
條款29:為“異常安全”而努力是值得的

異常安全的函數(shù)需要實(shí)現(xiàn)以下要求:

  • 不泄露任何資源:當(dāng)異常發(fā)生后乔遮,之前分配的資源不應(yīng)該沒(méi)有釋放扮超。
  • 不允許數(shù)據(jù)敗壞,主要是異常發(fā)生后要保證數(shù)據(jù)的一致性申眼。

異常安全有三個(gè)級(jí)別的承諾:

  • 基本承諾:異常發(fā)生后瞒津,系統(tǒng)的狀態(tài)不會(huì)出現(xiàn)不一致的情況,但是具體是什么狀態(tài)無(wú)法保證括尸。
  • 強(qiáng)烈保證:要么完全成功巷蚪,要么退回到函數(shù)調(diào)用前的狀態(tài)。
  • 不拋異常保證:函數(shù)執(zhí)行過(guò)程中保證不產(chǎn)生異常濒翻。

常用的異常安全實(shí)現(xiàn)方法是“copy and swap”方法屁柏,該方法步驟如下:
1、為你將要修改的對(duì)象有送,先建立一個(gè)副本淌喻;
2、在副本上進(jìn)行需要的修改雀摘;
3裸删、將原對(duì)象與副本對(duì)象進(jìn)行置換操作,并且保證調(diào)用的是一個(gè)不會(huì)拋出異常的swap操作阵赠,通常是兩個(gè)指針變量之間的交換涯塔;

條款30:透徹了解inlining的里里外外
  • inline函數(shù)的好處是可以像函數(shù)那樣調(diào)用肌稻,但是卻沒(méi)有函數(shù)調(diào)用的開(kāi)銷(xiāo);
  • 帶來(lái)的問(wèn)題是會(huì)增加程序代碼的大小匕荸,因?yàn)闀?huì)在調(diào)用的地方展開(kāi)爹谭。所以一般是將常用的并且短小的函數(shù)設(shè)置成inline。
  • class類(lèi)定義體中的實(shí)現(xiàn)函數(shù)默認(rèn)設(shè)置成inline方式榛搔。
  • 函數(shù)模板不要設(shè)置成inline方式诺凡,雖然一般是在頭文件中定義。
條款31:將文件間的編譯依存關(guān)系降至最低

我們?cè)诼暶饕粋€(gè)類(lèi)時(shí)践惑,如果成員變量中包含了其它類(lèi)時(shí)腹泌,則需要引用(include)其它類(lèi)的頭文件,因?yàn)榫幾g器在編譯這個(gè)類(lèi)時(shí)需要知道每個(gè)成員變量占用多大的空間童本。在這里真屯,該類(lèi)的聲明就在編譯層面與其它類(lèi)產(chǎn)生了依存關(guān)系脸候。

為了減少這種依存關(guān)系穷娱,在類(lèi)的定義中需要避免在成員變量中定義其它類(lèi)的對(duì)象,如果一定要定義运沦,最好采用引用或者指針(包括智能指針)形式泵额。這時(shí)候,可以在類(lèi)的頭文件中采用前置聲明的方式來(lái)引用其它類(lèi)携添,而不是直接inlcude其它頭文件嫁盲。

舉例:存在一個(gè)Date類(lèi)表示日期,Address類(lèi)表示地址烈掠,以及Person類(lèi)表示一個(gè)人羞秤,并且提供獲取此人生日和地址的方法。

  • Date.h
#ifndef UNTITLED6_DATE_H
#define UNTITLED6_DATE_H
class Date {
};

#endif //UNTITLED6_DATE_H
  • Address.h
#ifndef UNTITLED6_ADDRESS_H
#define UNTITLED6_ADDRESS_H
class Address {
};
#endif //UNTITLED6_ADDRESS_H
  • Person.h
#ifndef UNTITLED6_PERSON_H
#define UNTITLED6_PERSON_H
class Address; // 前置聲明
class Date;  // 前置聲明
class Person {
public:
    Address GetAddr();
    Date GetDate();
};
#endif //UNTITLED6_PERSON_H
  • Person.cpp
#include "Person.h"
#include "Address.h"
#include "Date.h"

Address Person::GetAddr()
{
    Address tmp;

    return tmp;
}

Date Person::GetDate()
{
    Date tmp;

    return tmp;
}

可以看到Person.h中并沒(méi)有include Date.h以及Address.h左敌,但是在cpp實(shí)現(xiàn)文件中需要引用涉及到的類(lèi)頭文件瘾蛋。

通過(guò)這種方式,將類(lèi)的編譯從相依于定義式轉(zhuǎn)變?yōu)橄嘁烙诼暶魇健?/p>

在接口類(lèi)的設(shè)計(jì)中矫限,為了盡可能降低接口類(lèi)編譯的依存關(guān)系哺哼,也采用了這種思路,有兩種做法:

  • handle class:在接口類(lèi)中定義一個(gè)實(shí)現(xiàn)類(lèi)的handle(引用或者指針)叼风,由實(shí)現(xiàn)類(lèi)完成與其他類(lèi)的編譯依存關(guān)系取董。
  • interface class:接口類(lèi)只包含虛函數(shù)功能接口,由具體的實(shí)現(xiàn)類(lèi)繼承接口類(lèi)進(jìn)行實(shí)現(xiàn)无宿,采用簡(jiǎn)單工廠模式創(chuàng)建具體的實(shí)現(xiàn)類(lèi)對(duì)象茵汰。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市孽鸡,隨后出現(xiàn)的幾起案子蹂午,更是在濱河造成了極大的恐慌坡垫,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件画侣,死亡現(xiàn)場(chǎng)離奇詭異冰悠,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)配乱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén)溉卓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人搬泥,你說(shuō)我怎么就攤上這事桑寨。” “怎么了忿檩?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵尉尾,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我燥透,道長(zhǎng)沙咏,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任班套,我火速辦了婚禮肢藐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘吱韭。我一直安慰自己吆豹,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布理盆。 她就那樣靜靜地躺著痘煤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪猿规。 梳的紋絲不亂的頭發(fā)上衷快,一...
    開(kāi)封第一講書(shū)人閱讀 51,301評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音坎拐,去河邊找鬼烦磁。 笑死,一個(gè)胖子當(dāng)著我的面吹牛哼勇,可吹牛的內(nèi)容都是我干的都伪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼积担,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼陨晶!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤先誉,失蹤者是張志新(化名)和其女友劉穎湿刽,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體褐耳,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡诈闺,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了铃芦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雅镊。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖刃滓,靈堂內(nèi)的尸體忽然破棺而出仁烹,到底是詐尸還是另有隱情,我是刑警寧澤咧虎,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布卓缰,位于F島的核電站,受9級(jí)特大地震影響砰诵,放射性物質(zhì)發(fā)生泄漏征唬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一胧砰、第九天 我趴在偏房一處隱蔽的房頂上張望鳍鸵。 院中可真熱鬧苇瓣,春花似錦尉间、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至媳禁,卻和暖如春眠副,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背竣稽。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工囱怕, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人毫别。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓娃弓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親岛宦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子台丛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容