Exceptional C++ 讀書(shū)筆記

?//內(nèi)存管理的一部分來(lái)自于http://blog.csdn.net/kingofark/category/9109.aspx
?Item 1 Iterator:
???
?(1): 注意當(dāng)前迭代器是否有效,如果無(wú)效則解引用產(chǎn)生程序錯(cuò)誤;
?(2):注意當(dāng)前迭代器生命期,某些容器經(jīng)過(guò)某些操作后將重新分配內(nèi)部存儲(chǔ)空間,則當(dāng)前迭代器無(wú)效;
?(3) : 有效范圍, 類似find(first, last, value)時(shí), 迭代器first 必須在last之前,必須保證指向同一個(gè)容器;
?????? (4): 有效的內(nèi)部操作;

?Item 2, 3: Case-Insensitive String
?????
?(1) 1 關(guān)于std::string: std::string實(shí)際是
??template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> >
??class basic_string;
??typedef basic_string<char> string;
??要實(shí)現(xiàn)case-insensitive string需要改變string的compare方式,因?yàn)閏har_traits<char>類提供compare等方式,所以
??就需要對(duì)char_traits<char>作相應(yīng)的變動(dòng);
??char_traits::eq()和lt()提供相等和小于的對(duì)比方式,compare()和find()提供對(duì)比和搜索字符串序列的功能;更改這四個(gè)成員函數(shù)??就可以實(shí)現(xiàn)case-insensitive string;
?(2)關(guān)于實(shí)際應(yīng)用中,最好選用一個(gè)單一的函數(shù)去接受兩個(gè)相應(yīng)的std::string對(duì)象,而非用更改traits的方法來(lái)實(shí)現(xiàn)一個(gè)ci_string;
?例如 bool CaseInsensitiveString(std::string &a, std::string &b)
?(3)類似ci_char_traits : public char_traits<char>, 用于變換traits或者iterator功能等情形,而非當(dāng)作傳統(tǒng)的OO方式來(lái)使用時(shí),可以當(dāng)作合理的派生,不必考慮virtual destructor等;
?
?Item 4, 5 Max Reusable Generic Containers
?(1) template constructor永遠(yuǎn)不會(huì)是一個(gè)copy constructor, 因?yàn)橛肋h(yuǎn)存在一個(gè)最適合的copy constructor, 因此overload resolution決不會(huì)將template constructor 當(dāng)作copy constructor
?
?(2) 善于使用模板成員函數(shù)

?Item 6, 7 Temporary Objects
?
?(1) a: 用傳遞const T& 代替?zhèn)髦?
???????? b: 用預(yù)先創(chuàng)建的對(duì)象代替不需要的重復(fù)創(chuàng)建的對(duì)象,類似(container.end()每次被調(diào)用將返回一個(gè)臨時(shí)的對(duì)象,這是不必要的);
???? c: 用++T 代替 T++ (因?yàn)門++ 一般先制造一個(gè)臨時(shí)對(duì)象,然后更新本身,最后返回臨時(shí)對(duì)象);
???????? d: 用++T來(lái)實(shí)現(xiàn)T++;
???? e: 避免做無(wú)用的隱式轉(zhuǎn)換;
?
?(2) 注意對(duì)象生命期,絕不準(zhǔn)讓函數(shù)返回一個(gè)函數(shù)內(nèi)部的auto變量的指針或者引用;
?(3) 多用標(biāo)準(zhǔn)庫(kù)的代碼;

?Item 8 -- 17 Writing Exception-Safe Code
?(1)當(dāng)一個(gè)函數(shù)不能處理內(nèi)部的異常時(shí),應(yīng)當(dāng)將它拋給函數(shù)調(diào)用者去處理;
?(2) 當(dāng)異常出現(xiàn)時(shí),請(qǐng)讓資源正確的被釋放,數(shù)據(jù)處于一個(gè)穩(wěn)定的狀態(tài);
?(3)絕不能讓從destructor或者被重載的delete中拋出,寫(xiě)析構(gòu)函數(shù)和資源分配函數(shù)時(shí)應(yīng)當(dāng)寫(xiě)上throw();?
?(4)先將所有可能拋出異常的操作和安全的的操作分離出來(lái),當(dāng)可能拋出異常的操作執(zhí)行成功時(shí),再用no throw操作改變對(duì)象狀態(tài);
?(5)讓每一個(gè)代碼片段(類,模塊,函數(shù))負(fù)責(zé)單一的任務(wù),類似STL stack中的pop和top是分離的
?
?(6): exception-safe基本準(zhǔn)則:
??A: 基本安全: 當(dāng)異常拋出時(shí)不產(chǎn)生資源泄漏;
??B: 健壯的安全性:如果某個(gè)操作因?yàn)楫惓5膾伋龆K止,則對(duì)象當(dāng)前狀態(tài)不應(yīng)改變;
??C: 不拋出異常: 約定這個(gè)函數(shù)決不拋出異常;
?
?(7): 將資源管理單獨(dú)的封裝成一個(gè)類類似書(shū)上的例子 StackImpl封裝了內(nèi)存管理功能
?(8): 多用聚合,少用繼承(包括這種聚合 pivate繼承 -- 因?yàn)檫@將導(dǎo)致在constructor中無(wú)法控制base class
?(9): 用資源申請(qǐng)既初始化來(lái)隔離類的實(shí)現(xiàn)和資源的管理與所有權(quán)
?
?(10): 什么時(shí)候應(yīng)當(dāng)用private繼承代替containment?
??a: 需要存取某個(gè)類的protected成員
??b: 需要覆寫(xiě)虛函數(shù)
??c: base 對(duì)象需要在其他類對(duì)象建構(gòu)之前建構(gòu)
?(11): 析構(gòu)函數(shù)中決不允許拋出異常:
??a: 對(duì)象本身所申請(qǐng)的的資源不能完全釋放;
??b:考慮 T t[20];的情況;析構(gòu)某個(gè)T時(shí)拋出異常會(huì)產(chǎn)生未定義情況
??
Item 18, 19 Code Complexity
?(1): 提供強(qiáng)異常安全需要損失一定程度的性能;
?(2): 如果一個(gè)函數(shù)存在幾個(gè)不相關(guān)的副作用,那么它不可能實(shí)現(xiàn)異常安全, 否則應(yīng)當(dāng)把這幾個(gè)函數(shù)分割為不同的函數(shù)
?(3): 不是所有的函數(shù)都需要強(qiáng)異常安全;

?Item 20 Class Mechanics
?(1):?設(shè)計(jì)時(shí)首先考慮標(biāo)準(zhǔn)庫(kù)是否存在相關(guān)的類
?(2): ?用explicit constructor代替隱式轉(zhuǎn)換
?(3): 如果提供一個(gè)常規(guī)的operator op(類似+),那么應(yīng)該同樣提供一個(gè)operator op=(+=),
??operator op(類似的 + - * /)不應(yīng)該改變對(duì)象值, 它應(yīng)當(dāng)返回一個(gè) + 操作后的臨時(shí)對(duì)象;
?(4): 多用a op= b 代替 a = a op b; 一般 const T operator op(T, T)產(chǎn)生一個(gè)臨時(shí)變量;
?
?(5) ?一元運(yùn)算符是成員函數(shù)
?????? =,(),[]和->必須是成員函數(shù)
?????? +=,-=,/=,*=(等等)是成員函數(shù)
?????? 所有其它的二元運(yùn)算符是非成員函數(shù)
?(6) ++T 應(yīng)當(dāng)返回一個(gè)引用, T++應(yīng)當(dāng)返回一個(gè)const T,以防止 T++++這種情況發(fā)生;T++應(yīng)當(dāng)由++T來(lái)實(shí)現(xiàn);
?(7) 避免使用前導(dǎo)下劃線來(lái)命名,前導(dǎo)下劃線是留給編譯器使用的
?
?Item 21 override 虛函數(shù)?
?(1): 除非確定某個(gè)類不被派生,否則都應(yīng)當(dāng)提供一個(gè)虛函數(shù);
?(2): 關(guān)于 overload, override和 hide
??a: overload意思是提供一個(gè)相同名稱但是不同參數(shù)的函數(shù), 編譯時(shí)由編譯器決定哪個(gè)是最匹配的函數(shù)
??b: override意思是在派生類提供一個(gè)相同名稱且相同參數(shù)不同實(shí)現(xiàn)的虛函數(shù),動(dòng)態(tài)調(diào)用時(shí)將從派生類指針調(diào)用這個(gè)函數(shù)
??c: hide 某個(gè)函數(shù)的意思是有一個(gè)函數(shù)在某個(gè)范圍內(nèi)(派生類,嵌套類,名稱空間等),隱藏同名函數(shù)
??
?(3) 當(dāng)派生類提供一個(gè)和基類的某個(gè)成員函數(shù)同名的函數(shù)時(shí),如果你不想隱藏基類的同名函數(shù),請(qǐng)?jiān)谂缮惵暶骰惖耐瘮?shù),
??例如: using Base::f;
?(4) 永遠(yuǎn)不要在派生類override virtual function中改變默認(rèn)參數(shù);
?
?Item 22, 23 Class Relationships
?(1): 什么時(shí)候不應(yīng)該選用public 繼承
????? a: 如果某個(gè)類為提供虛函數(shù),這個(gè)類本身不打算實(shí)施多態(tài);
????? b: 如果某個(gè)類未提供protected 成員
????? c: 類型為不是IS-A, WORKS-LIKE-A or USABLE-AS-A;
????? d: 派生類只用了基類的public 成員;
?(2): 只有當(dāng)需要存取某個(gè)類protected 成員或者override 虛函數(shù)的時(shí)候才應(yīng)該選用private繼承;不是IS-A, WORKS-LIKE-A or
????? USABLE-AS-A的時(shí)候決不應(yīng)當(dāng)用public 繼承;
?
?(3): 避免提供public virtual function, 使用template method 設(shè)計(jì)模式代替;從算法中提取出那些每次都要進(jìn)行的步驟,將其抽象出??來(lái),只把一些因地制宜的細(xì)節(jié)通過(guò)virtual function 留給派生類來(lái)實(shí)現(xiàn)。
?(4): 應(yīng)用compiler-firewall 方法隱藏實(shí)現(xiàn)細(xì)節(jié),使用一個(gè)不透明的指針(指向一個(gè)聲明但未定義的類
??(struct xxxImpl; xxxImpl *pimpl_)來(lái)存private 成員,包括狀態(tài)變量和成員函數(shù));
??例如: clas Map { private: struct MapImpl; MapImpl *pimpl_; };
?
?
?Item 24 Uses and Abuses of Inheritance
?(1): 多用聚合,(containment, composition, layering HAS-A, delegation),當(dāng)關(guān)系模型為 IS-IMPLEMENTED-IN-TERMS-OF時(shí),請(qǐng)多考慮聚合,最好不用繼承;
?(2): 非public 繼承的條件:
??a: 當(dāng)需要override virtual function時(shí)候;
??b: 需要存取基類protected成員時(shí)候
??c: 需要保證初始化順序的時(shí)候(基類必須建構(gòu)在派生類之前,析構(gòu)在派生類之后等情況);
??d: 需要某種多態(tài)的訪問(wèn)控制時(shí);
?(3): 用public繼承時(shí)應(yīng)當(dāng)避免的問(wèn)題:
??a: 如果非public繼承可以做,那么決不要用public繼承;絕不能用public繼承表述一個(gè)依據(jù)什么實(shí)現(xiàn)的關(guān)系模型;
??b: 絕不能用public繼承表述一個(gè) IS-ALMOST-A關(guān)系模型(類似正方形是一個(gè)矩形等關(guān)系模型);
?(4): 應(yīng)當(dāng)總是先確定 public繼承關(guān)系模型為 IS-A或者WORKS-LIKE-A

?Item 25 Object-Oriented Programming
?略;
?Item 26-28 Minimizing Compile-Time Dependencies
?(1): 決不#include無(wú)用的頭文件;
?(2): 當(dāng)前向聲明某個(gè)stream時(shí)候用<iosfwd>足夠了;
?(3): 如果composition足夠的話,決不能用繼承;
?
?Item 29 Compilation Firewalls
?(1): 放置所有的非virtual函數(shù) private member 到Pimpl類中去; 客戶程序員無(wú)論如何也不應(yīng)當(dāng)看到這些private成員;
????? Pimpl類中某些函數(shù)可能需要類中某些成員的支持,所有需要一個(gè)back pointer指向類本身,back pointer通常命名為self_
?
?Item 30 The "Fast Pimpl" Idiom
?(1):絕不能放置對(duì)象到一個(gè)buffer里面,例如
??char buffer[100];
??new (&buffer[0]) T;
??a: 不能保證對(duì)齊規(guī)則;
??b: 脆弱
??c: 難于維護(hù);
??
?
?Item 31 - 34 Name Lookup and Interface Principle
?(1): 對(duì)于一個(gè)class X,任何提及并且含有X(例如來(lái)自同一頭文件或者名稱空間)的函數(shù)(括成員函數(shù),static函數(shù)和自由函數(shù)),邏輯上都屬于class X的一部分,因?yàn)樗鼈兪荴接口的一部分
??任何class X的成員函數(shù)都一定提及X;
??任何class X的成員函數(shù)都一定含有X(隱式的this);

??例如:
???class X{...};
???ostream& operator<<(ostream&, const X&)//肯定提及X;
???如果operator<<含有X ,例如在同一個(gè)頭文件或者名稱空間,那么它邏輯上屬于X的一部分,因?yàn)樗?gòu)了X的一部分接口;
???否則反之;
??
?(2): 關(guān)于 supplied with;
??struct _iobuf{...};
??typedef struct _iobuf FILE;
??FILE*?fopen(const char *filename, const char* mode);
??int fclose(FILE* stream);
??int fseek(FILE* stream, long offset, int origin);
??......
??這些函數(shù)都是非成員,但是它們確實(shí)是 FILE接口的一部分;(part of the interface of FILE);
??class File
??{
??public:
???int fseek(long offset, int origin);
???......
??};
??int fseek(FILE* stream, long offset, int origin);
??例如上例:?int fseek(FILE* stream, long offset, int origin);
??提及并且同F(xiàn)ile都來(lái)自于頭一個(gè)頭文件或者名稱空間,此函數(shù)一樣屬于File接口的一部分;
?
?(3):如果在某個(gè)作用域內(nèi)調(diào)用了一個(gè)接受另一個(gè)作用域內(nèi)類型參數(shù)的函數(shù),那么編譯器不止在當(dāng)前作擁域內(nèi)查找該函數(shù),同時(shí)也會(huì)到接受的的??類型所在的作用域去查找該函數(shù),而且不用特別聲明;類似
??void f()
??{
???std:string hello = "hello world";
???std::cout? <<? hello;?? //正確調(diào)用std::operator<<;
??}
?? 如果沒(méi)有Koenig lookup,則編譯器無(wú)法查找到operator<<是哪一個(gè)我們想要的;(這個(gè)函數(shù)封裝在std::string內(nèi),是string接口 的??一部分);如果希望正確調(diào)用的operator<<,我們需要 std::operator<<(std::cout, hello);
??
??所以,如果在同一個(gè)名稱空間內(nèi)定義了一個(gè)類和一個(gè)提及這個(gè)類的函數(shù), 那么編譯器將強(qiáng)制關(guān)聯(lián)這個(gè)類和這個(gè)自由函數(shù);
?(4): namespace A { class X {};? void f(X x) {} }
??namespace B { void f(A::X x) {} void g(A:: xx) { f(xx); } }
??這將導(dǎo)致B::g出現(xiàn)二義性而無(wú)法編譯;原因在于g涉及A::X,所以編譯時(shí)編譯器同樣將名稱空間A內(nèi)的函數(shù)也考慮進(jìn)來(lái),此時(shí)出現(xiàn)兩個(gè)參??數(shù)為A::X的函數(shù)f
??類的成員函數(shù)將被優(yōu)先考慮,例如
??namespace A { class X {};? void f(X x) {} }
??class B
??{
???void f(A::X x) {}
???void g(A:: xx) { f(xx); } //此時(shí)不會(huì)出現(xiàn)二義性問(wèn)題;
??};
??如果編譯器發(fā)現(xiàn)一個(gè)類成員函數(shù)為f(A::X),則不再使用Koenig lookup去搜索自由函數(shù);
??
?(5):結(jié)論為名稱空間不像想象的那樣完全隔離函數(shù)聲明,它只能屬于部分獨(dú)立;
?
?
?(6): 根據(jù)Interface Principle,如果一個(gè)函數(shù)提及了兩個(gè)類,class X和class Y, 并且此函數(shù)同X包含在同一個(gè)名稱空間或者頭文件之中,那么,首先,此函數(shù)邏輯上是X的界面接口的一部分;由于此函數(shù)依賴Y,因此,X同樣依賴于Y;
?(7): 如果A,B是類,f(A,B)是自由函數(shù), 那么
??a: 如果A和f在同一頭文件或名稱空間內(nèi),那么f邏輯上是A的一部分,所以,A也依賴于B;
??b: 如果A,B和f在同一頭文件或名稱空間內(nèi),那么f邏輯上是A的一部分也是B的一部分,故此,A,B互相依賴;
?
??如果 ,A,B是類,A::g(B)是一個(gè)A的成員函數(shù),那么:
??a: 因?yàn)锳::g(B),所以,A,依賴于B;
??b:如果A,B被聲明在一起(同一個(gè)頭文件或名稱空間),那么A,B互相依賴,A::g(B)邏輯上同樣屬于B的一部分;
??實(shí)際上,上述情況的實(shí)際含義是,類型A,B通常將被放在一起使用,,如果修改了一個(gè),那么將影響另一個(gè);
?(8):關(guān)于名稱隱藏:
??struct B
??{
???int f(int);
???int f(double);
???int g(int);
??};
??struct D : public B
??{
??private:
???int g(std::string, bool);
??};
??D d;
??int i;
??d.f(i) ?//調(diào)用B::f(int);
??d.g(i);?//錯(cuò)誤,提示應(yīng)當(dāng)提供兩個(gè)參數(shù);
??
??? 實(shí)際上,編譯器查找匹配函數(shù)名稱時(shí)候,先查找當(dāng)前范圍內(nèi)的名稱匹配函數(shù),例如這里是D,然后列出一個(gè)編譯器所能找到的函??數(shù)名稱?相同的函數(shù)的列表,但 是并不考慮存取權(quán)限和所攜帶參數(shù)是否正確,如果它一個(gè)名稱匹配的函數(shù)都沒(méi)找到的話,那么將向外一層??繼續(xù)查找,如果編譯器找到一個(gè)或者多個(gè)候選的函數(shù), 編譯器將停止查找,然后提交函數(shù)的重載決議;
??兩種解決方法是
??a: d.B::g(i);//編譯器自然會(huì)考慮B的范圍;
??b:
???struct D : public B
???{
???using B::g;
???private:
????int g(std::string, bool);
???};
??
??
??
?(9): 使用名稱空間,如果寫(xiě)一個(gè)類在名稱空間N中,那么請(qǐng)將所有的協(xié)助函數(shù)和操作符都都寫(xiě)在N中;
Item 35, 36 Memory Management
?
?(1):
??[常量數(shù)據(jù)(const data)區(qū):]
??常量數(shù)據(jù)區(qū)存儲(chǔ)字符串等在編譯期間就能確定的值。類對(duì)象不能存在于這個(gè)區(qū)域中。在程 序的整個(gè)生存周期內(nèi),區(qū)域中的數(shù)據(jù)都是可??用的。區(qū)域內(nèi)所有的數(shù)據(jù)都是只讀的,任何企圖修改本區(qū)域數(shù)據(jù)的行為都會(huì)造成無(wú)法預(yù)料的后果。之所以會(huì)如此,是 因?yàn)樵趯?shí)際的實(shí)現(xiàn)??當(dāng)中,即使是最底層的內(nèi)部存儲(chǔ)格式也受制于所實(shí)現(xiàn)的特定的優(yōu)化方案。例如,一種編譯器完全可以把字符串存放在幾個(gè)重疊的對(duì)象里??面 ——只要實(shí)現(xiàn)者愿意的話。?
??[棧(stack)區(qū):]
??棧區(qū)存儲(chǔ)自動(dòng)變量(automatic variables)。一般來(lái)說(shuō),棧區(qū)的分配操作要比動(dòng)態(tài)存儲(chǔ)區(qū)(比如堆(heap)或者自由存儲(chǔ)區(qū)(free ??store))快得多,這是因?yàn)闂^(qū)的分配只涉及到一個(gè)指針的遞增,而動(dòng)態(tài)存儲(chǔ)區(qū)的分配涉及到較為復(fù)雜的管理機(jī)制。棧區(qū)中,內(nèi)存一??旦被分配,對(duì)象 就立即被構(gòu)造好了;對(duì)象一旦被銷毀,分配的內(nèi)存也立即被收回(譯注:這里作者用了“去配(deallocate)”一詞,??鄙人一律翻譯為“回收”)。 因此,在棧區(qū)中,程序員沒(méi)有辦法直接操縱那些已經(jīng)被分配但還沒(méi)有被初始化的棧空間(當(dāng)然,那些通過(guò)??使用顯式(explicit)析構(gòu)函數(shù) (destructor)和new運(yùn)算符而故意這么做的情況不算在內(nèi))。
??[自由存儲(chǔ)區(qū)(free store):]
? ??自由存儲(chǔ)區(qū)(free store)是C++兩個(gè)動(dòng)態(tài)內(nèi)存區(qū)域之一,使用new和delete來(lái)予以分配和釋放(freed)。在自由存儲(chǔ)區(qū)(free ???store)中,對(duì)象的生存周期可以比存放它的內(nèi)存區(qū)的生存周期短;這也就是說(shuō),我們可以獲得一片內(nèi)存區(qū)而不用馬上對(duì)其進(jìn)行初始??化;同時(shí),在對(duì) 象被銷毀之后,也不用馬上收回其占用的內(nèi)存區(qū)。在對(duì)象被銷毀而其占用的內(nèi)存區(qū)還未被收回的這段時(shí)間內(nèi),我們可以??通過(guò)void*型的指針訪問(wèn)這片區(qū)域, 但是其原始對(duì)象的非靜態(tài)成員以及成員函數(shù)(即使我們知道了它們的地址)都不能被訪問(wèn)或者操??縱。
??
??[堆(heap)區(qū):]
?? 堆(heap)區(qū)是另一個(gè)動(dòng)態(tài)存儲(chǔ)區(qū)域,使用malloc、free以及一些相關(guān)變量來(lái)進(jìn)行分配和回收。要注意,雖然在特定的編譯器里缺省的??全局運(yùn)? 算符new和delete也許會(huì)按照malloc和free的方式來(lái)被實(shí)現(xiàn),但是堆(heap)與自由存儲(chǔ)區(qū)(free store)是不同的——在某??一個(gè)區(qū)域內(nèi)被分配的內(nèi)存不可能在另一個(gè)區(qū)域內(nèi)被安全的回收。堆(heap)中被分配的內(nèi)存一般用于存放在使用new的構(gòu) 造過(guò)程中和顯??式(explicit)的析構(gòu)過(guò)程中涉及到的類對(duì)象。堆中對(duì)象的生存周期與自由存儲(chǔ)區(qū)(free store)中的類似。
??[全局/靜態(tài)區(qū)(Global/Static):]
?? ??全局的或靜態(tài)的變量和對(duì)象所占用的內(nèi)存區(qū)域在程序啟動(dòng)(startup)的時(shí)候才被分配,而且可能直到程序開(kāi)始執(zhí)行的時(shí)候才被初始??化。比如,函數(shù) 中的靜態(tài)變量就是在程序第一次執(zhí)行到定義該變量的代碼時(shí)才被初始化的。對(duì)那些跨越了翻譯單元(translation ???unit)的全局變量進(jìn)行初始化操作的順序是沒(méi)有被明確定義的,因而需要特別注意管理全局對(duì)象(包括靜態(tài)類對(duì)象)之間的依賴關(guān)系。??最后,和前面 講的一樣,全局/靜態(tài)區(qū)(Global/Static)中沒(méi)有被初始化的對(duì)象存儲(chǔ)區(qū)域可以通過(guò)void*來(lái)被訪問(wèn)和操縱,但是只要是??在對(duì)象真正的生存 周期之外,非靜態(tài)成員和成員函數(shù)是無(wú)法被使用或者引用的。
??
??[關(guān)于“堆(heap)vs.自由存儲(chǔ)區(qū)(free store)”]:
??本條款中我們將堆(heap)和自由存儲(chǔ)區(qū)(free store)區(qū)分開(kāi)來(lái),是因?yàn)樵贑++標(biāo)準(zhǔn)草案中,關(guān)于這兩種區(qū)域是否有聯(lián)系的問(wèn)題一直??很謹(jǐn)慎的沒(méi)有予以詳細(xì)說(shuō)明。比如當(dāng)內(nèi)存在通過(guò)delete運(yùn)算符進(jìn)行回收時(shí),18.4.1.1中說(shuō)道:
???It is unspecified under what conditions part or all of such reclaimed storage is allocated by a ????subsequent call to operator new or any of calloc, malloc, or realloc, declared in <cstdlib>.
???[關(guān)于在何種情況下,這種內(nèi)存區(qū)域的部分或全部才會(huì)通過(guò)后續(xù)的對(duì)new(或者是在<cstdlib>里聲明的calloc,malloc,????realloc中的任何一個(gè))的調(diào)用來(lái)被分配的問(wèn)題,在此不作詳細(xì)規(guī)定,不予詳述。]
?
?????? 同樣,在一個(gè)特定的實(shí)現(xiàn)中,到底new和delete是按照malloc和free來(lái)實(shí)現(xiàn)的,或者反過(guò)來(lái)malloc和free是按照new和 delete來(lái)實(shí)現(xiàn)??的,這也沒(méi)有定論。簡(jiǎn)單地說(shuō)吧,這兩種內(nèi)存區(qū)域運(yùn)作方式不一樣,訪問(wèn)方式也不一樣——所以嘛,當(dāng)然應(yīng)該被當(dāng)成不一樣的兩個(gè)東西?? 來(lái)使用了!
?
?Item 37: AUTO_PTR
??略
?Item 38 Object Identity
?(1): 千萬(wàn)別寫(xiě)一個(gè)依賴于檢測(cè)自身賦值達(dá)到正確操作的operator=(),一個(gè)拷貝賦值操作符應(yīng)當(dāng)使用create-a-temporary-and-swap
??方法來(lái)自動(dòng)維持強(qiáng)異常安全和安全的自身賦值;
?
?(2): 自身賦值是個(gè)可行的優(yōu)化去避免無(wú)用的工作;
?
?Item 39 Automatic Conversions
?
?(1): 避免使用隱式轉(zhuǎn)換操作符:
??a: 隱式轉(zhuǎn)換會(huì)影響重載決議;
??b: 隱式轉(zhuǎn)換會(huì)讓錯(cuò)誤的代碼安靜的編譯通過(guò);
?(2):?C++標(biāo)準(zhǔn)保證「對(duì)指向同一個(gè)對(duì)象的多個(gè)指針的比較之結(jié)果必須是“相等(equal)” 」,但卻并不保證「對(duì)指向不同對(duì)象的多個(gè)指針??的比較之結(jié)果必須是“不相等(unequal)”」。
?Item 40,41 Object Lifetimes
?
?(1):?void f()
??{
???T t(1);
???T& rt = t;
???//#1 ?do something;
???t.~T();
???new (&t) T(2);
???//#2 ?do something;
??};
?a: #2是合法的;
?b: #2是不安全的;
?請(qǐng)總是嘗試寫(xiě)異常安全級(jí)別的代碼, 總是嘗試正確的組織代碼讓資源正確的申請(qǐng)和釋放當(dāng)異常拋出時(shí);
?
?(2): 避免C++ 語(yǔ)言級(jí)別定義不太明確的技巧,應(yīng)該多用清晰簡(jiǎn)單的編程技巧;???
?(3): 用同一個(gè)成員函數(shù)完成兩種拷貝操作(拷貝構(gòu)造和拷貝賦值)的注意是很好的:這意味著我們只需在一個(gè)地方編寫(xiě)和維護(hù)操作代碼。本條??款問(wèn)題中的慣用法只不過(guò)是選擇了錯(cuò)誤的函數(shù)來(lái)做這件事。如此而已。
?
??其實(shí),慣用法應(yīng)該是反過(guò)來(lái)實(shí)現(xiàn)的:拷貝構(gòu)造操作應(yīng)該以拷貝賦值操作來(lái)實(shí)現(xiàn),不是反過(guò)來(lái)實(shí)現(xiàn)。例如:
??T::T( const T& other ) {
??????? /* T:: */ operator=( other );
??}
??? ??
??T& T::operator=( const T& other ) {
?????? ?// 真正的工作在這里進(jìn)行
????? ??// (大概可以在異常安全的狀態(tài)下完成,但現(xiàn)在
????? ??// 其可以拋出異常,卻不會(huì)像原來(lái)那樣產(chǎn)生什么不良影響
???? ?? ?return *this;
??? ??}
??這段代碼擁有原慣用法的所有益處,卻不存在任何原慣用法中存在的問(wèn)題。[注5] 為了代碼的美觀,你或許還要編寫(xiě)一個(gè)常見(jiàn)的私有輔??助函數(shù),利用其做真正的工作;但這也是一樣的,無(wú)甚區(qū)別:
??? ??T::T( const T& other ) {
????? ??do_copy( other );
??? ??}
??? ??
??T& T::operator=( const T& other ) {
????? ??do_copy( other );
????? ??return *this;
??? ??}
??? ??
??T& T::do_copy( const T& other ) {
????? ??// 真正的工作在這里進(jìn)行
????? ??// (大概可以在異常安全的狀態(tài)下完成,但現(xiàn)在
????? ??// 其可以拋出異常,卻不會(huì)像原來(lái)那樣產(chǎn)生什么不良影響
??}
?
?

??如果需要的話,請(qǐng)編寫(xiě)一個(gè)私有函數(shù)來(lái)使拷貝操作和拷貝賦值共享代碼;千萬(wàn)不要利用「使用顯式的析構(gòu)函數(shù)并且后跟一個(gè) placement ??new」的方法來(lái)達(dá)到「以拷貝構(gòu)造操作實(shí)現(xiàn)拷貝賦值操作」這樣的目的,即使這個(gè)所謂的技巧會(huì)每隔三個(gè)月就在新聞組中出現(xiàn)幾次。??(也就是說(shuō),決不要 編寫(xiě)如下的代碼:)
??????? ?T& T::operator=( const T& other )
??????? ?{
??????????? ?if( this != &other)
??????????? ?{
??????????????? ??this->~T();???????????? // 有害!
??????????????? ??new (this) T( other );? // 有害!
??????????? ?}
??????????? ?return *this;
??????? ?}
?

?Item 42: Variable Initialization -- Or is it?
?(1): 關(guān)于 T u; T t = u;
??這時(shí),編譯器總會(huì)是調(diào)用 copy-construct而不是調(diào)用默認(rèn)constructor之后調(diào)用operator=(),這只是一個(gè)從C繼承來(lái)的語(yǔ)法,???并沒(méi)有賦值操作
?(2): 用 T t(u);代替 T t = u;

?Item 43 Const-Correctiness;
?(1): 避免在某個(gè)函數(shù)參數(shù)使用 const by value
?(2): 如果是非內(nèi)部類型的return by value,那么優(yōu)先考慮返回一個(gè)const value;
?(3): 如果某個(gè)類數(shù)據(jù)成員的改變并不影響到類狀態(tài)的改變,例如class X { private: char buffer[1024]; ...};
??那么當(dāng)某函數(shù)只改變這個(gè)類數(shù)據(jù)成員,而不改變其他成員時(shí),也應(yīng)當(dāng)把這個(gè)函數(shù)為const ,并將這個(gè)被改變但無(wú)關(guān)類狀態(tài)的成員聲明為
??mutable;

?Item 44 Casts
?(1): 請(qǐng)優(yōu)先使用新轉(zhuǎn)型風(fēng)格cast;
?(2): 避免用const_cast消除const ,請(qǐng)優(yōu)先使用mutable;
?(3): 避免動(dòng)態(tài)的向下轉(zhuǎn)型;
?Item 45: BOOL
?略
?Item 46 Forwarding Functions;
?(1): 多考慮傳遞對(duì)象的const &;
?(2): 避免語(yǔ)言的隱晦角落,多用簡(jiǎn)單的技巧;
?(3): 如果不認(rèn)為性能上絕對(duì)需要,請(qǐng)避免inline或者內(nèi)部?jī)?yōu)化;

?Item 47 Control Flow
?(1): 避免使用全局或者靜態(tài)變量;如果必須如此,那么請(qǐng)注意它們的初始化順序(因?yàn)槎鄠€(gè)頭文件內(nèi)引入的靜態(tài)變量的聲明順尋并不是標(biāo)準(zhǔn)定??義的);
?(2): 將基類的constructor在初始化器列表中的順序和類聲明的順序是一樣的,基類的初始化順序是依據(jù)類定義時(shí)的順序的;
?(3): 將類的數(shù)據(jù)成員的初始化順序與初始化器列表中聲明的順序是一樣的,同樣依據(jù)類定義;
?(4): 努力去實(shí)現(xiàn)代碼的異常級(jí)安全;
?(5): 絕不能寫(xiě)依賴函數(shù)參數(shù)賦值順序的代碼;