Part1一、讓自己習慣C++
條款01:視C++為一個語言聯(lián)邦
C++并不是一個帶有一組守則的一體語言:他是從四個次語言( C、Object-Oriented C++、Template、STL ) 組成的聯(lián)邦政府,每個次語言都有自己的規(guī)約。記住這四個次于語言你就會發(fā)現(xiàn)C++容易了解得多。
條款02:盡量以const,enum,inline替換 #define
#define ASPECT_RATIO 1.653
以上句為例,是通過預處理器處理而不是編譯器處理,有可能ASPECT_RATIO 沒進入記號表內,于是如果出現(xiàn)了編譯錯誤,那么編譯器會提示錯誤信息是 1.653 而不是 ASPECT_RATIO ,你會感到非常困惑。
解決方法是用常量替換宏
const double AspectRatio = 1.653
這樣編譯器就可以看到ASPECT_RATIO ,而且使用常量會使代碼量較小,因為預處理器只會盲目的替換而出現(xiàn)多份 1.653
string對象通常比char* 更好一點
對于class的專屬常量,為了限制作用域在class內,并且防止產生多個實體,最好使用static
1. 如果你的編譯器支持在類內對const static 整數(shù)類型聲明時獲初值,則使用
2. 如果不支持,則在類內定義,在對應的實現(xiàn)文件中賦值
如果你需要在編譯器就使用一個class常量值,則應最好改用枚舉類型enum,且枚舉不能用來取地址,不會為它分配額外的存儲空間對于形似函數(shù)的宏,最好改用inline的模板函數(shù)
條款 03:盡可能使用const
const出現(xiàn)在星號左邊目標是指物是常量,出現(xiàn)在星號右邊表示指針本身是常量,如果出現(xiàn)在兩邊,則指針和物都是常量void f1(const Widget* pw)和void f2(Widget const* pw)兩種寫法意義相同,都表示被指物是常量 對于STL迭代器來說,如果你希望迭代器所指的動科不可改動,你需要的是const_iterator 令函數(shù)返回一個常量值,往往可以降低因客戶錯誤而造成的意外(例如把一個值賦值給一個返回值) 將const實施與成員函數(shù)的目的是為了明確該成員函數(shù)可作用于const對象:
1. 他們使class接口比較容易理解
2. 他們使得可以操作const對象
const成員函數(shù)和no-const成員函數(shù)可重載,即可以同時出現(xiàn),在傳入不同的參數(shù)時候會調用不同的版本,但是有時我們需要這樣,但是又不想代碼重復,我們可以在no-const成員調用const成員函數(shù)來處理這個代碼重復問題 例如:const_cast<char &>( static_cast<const TextBlock&>(*this)[position]);,經過這樣里面 先安全轉型使得調用的是const版本,外面再去const轉型
條款 04:確定對象被使用前已先被初始化
對于內置類型要進行手工初始化構造函數(shù)最好使用成員初值列表,不要在構造函數(shù)中使用賦值操作來初始化,而且初值列表列出的成員變量次序應該和在class中聲明的次序一樣,因為聲明次序就是C++保證的初始化次序 對于static對象,在跨編譯單元之間的初始化次序是不能確定的,因為C++只保證在本文件內使用之前一定被初始化了
舉例(使用如下方式可以解決這個問題即以loacl static對象替換non-local static對象):
- class FileSystem{...};
- FileSystem& tfs(){
- static FileSystem fs;
- return fs;
- }
Part2二、構造/析構/賦值運算
條款05:了解C++默默編寫并調用了哪些函數(shù)
如果你不定義,編譯器會自動幫你實習默認的構造函數(shù),析構函數(shù),拷貝賦值運算符和拷貝構造函數(shù),但是如下幾種情況不會替你生成默認的拷貝賦值運算符
1. 類中含有**引用**的成員變量
2. 類中含有**const**的成員變量
3. 類的**基類**中的拷貝賦值運算符是**私有**成員函數(shù)
條款06:若不想使用編譯器自動生成的函數(shù),就應該明確拒絕
當我們不希望編譯器幫我們生成相應的成員函數(shù)的時候,我們可以將其聲明為private并且不予以實現(xiàn)
條款07:為多態(tài)基類聲明virtual析構函數(shù)
以下情況應該為類聲明一個virtual析構函數(shù):
1. 用來作為帶有多態(tài)性質的基類的類
2. 一個類中帶有任何virtual函數(shù)
如果類的設計目的不是作為基類使用,那么就不應該為它聲明virtual析構函數(shù)
條款08:別讓異常逃離析構函數(shù)
析構函數(shù)不要吐出異常,如果實在要拋出異常,那么最好使用std::abort();,放在catch中,把這個行為壓下去 如果某個動作可能會拋出異常,那么最好把它放在普通函數(shù)中,而不是放在析構函數(shù)里面,讓客戶來執(zhí)行這個函數(shù)并去處理
條款09:絕不再構造和析構函數(shù)中調用virtual函數(shù)
在構造和析構的時候,不要試圖調用或在調用的函數(shù)中調用virtual函數(shù),因為會調用父類版本導致出現(xiàn)一些未定義的錯誤
解決辦法之一:
- class Transaction{
- publci:
- explicit Transaction(const std::string& logInfo);
- void logTransaction(const std::string& logIngo) const;//把它變成這樣的non-virtual函數(shù)
- ...
- };
- Transaction::Transaction(const std::string& logInfo){
- ...
- logTransaction(logInfo);//這樣調用
- }
- class BuyTransaction: public Transaction{
- BuyTransaction( parameters ):Transaction(createLogString( parameters )){...}//將log信息傳給基類的構造函數(shù)
- private:
- static std::string createLogString( parameters );//注意此函數(shù)為static函數(shù)
- }
條款10:令operator= 返回一個reference to *this
為了實現(xiàn)連鎖賦值如內置類型x= y = z =15由于=采用右結合律,所以等價于x = (y = (z = 15)),因此,為了使我們自定義類也實現(xiàn),所以*重載=,+=,-=,*=使其返回refercence to this
條款11:在operator= 中處理“自我賦值”
在賦值的時候會出現(xiàn)對自我進行賦值的情況,這種情況下我們很容易寫出不安全的代碼
- Widget::operator=(const Widget& rhs){
- delete pb; //把自己釋放了
- pb = new Bitmap(*rhs.pb);//這就不安全了
- return *this;
- }
因此有三種推薦的做法
- 先驗證是不是相同的,是不是自我賦值
- Widget::operator=(const Widget& rhs){
- if(this == &rhs) return *this;//驗證是不是相同
- delete pb;
- pb = new Bitmap(*rhs.pb);
- return *this;
- }
2. 在復制pb所指的東西之前別刪除pb
- Widget::operator=(const Widget& rhs){
- Bitmap* pOrig = pb;
- pb = new Bitmap(*rhs.pb);//讓pb指向*pb的一個副本
- delete pOrig; //刪除原先的pb
- return *this;
- }
3. 使用交換數(shù)據(jù)的函數(shù)
- class Widget{
- ...
- void swap(Widget& rhs);//交換*this和rhs的數(shù)據(jù)
- ...
- };
- Widget::operator=(const Widget& rhs){
- Widget temp(rhs);//創(chuàng)建一個rhs副本
- swap(temp);//交換*this和上面的副本
- return *this;
- }
條款12:復制對象時勿忘其每一個成分
為了確保復制的時候復制對象內的所有成員變量,我們應該在字類的構造和賦值函數(shù)中調用父類的構造和賦值函數(shù)來完成各自的任務 不要嘗試在復制構造函數(shù)和賦值函數(shù)中相互調用,如果想消除重復代碼,請建立一個新的成員函數(shù),并且最好將其設為私有且命名為init
Part3三、資源管理
條款13:以對象管理資源
為了防止資源泄露,我們應該在構造函數(shù)中獲取資源,在析構函數(shù)中釋放資源,這樣可以有效的避免資源泄露 使用智能指針是一個好的辦法,在C++11中auto_ptr已經被棄用,有三個常用的是unique_ptr,share_ptr和weak_ptr
條款14:在資源管理類中心copying行為
我們在管理RAII(構造函數(shù)中獲得,析構函數(shù)中釋放)觀念的類時,應該對不同的情況,根據(jù)不同的目的進行處理
1. 當我們處理不能同步擁有的資源的時候,可以才用**禁止復制**,如把copying操作聲明為private
2. 當我們希望共同擁有資源的時候,可以采用**引用計數(shù)法**,例如使用shared_ptr
3. 當我們需要拷貝的時候,可以采用**深拷貝**
4. 或者某些時候我們可以采用**轉移**底部資源擁有權的方式
條款15:在資源管理類中提供對原始資源的訪問
有的api函數(shù)往往需要訪問類的原始資源,所以每一個RAII類應該提供一個返回其管理的原始資源的方法 返回原始資源可以使用顯示轉換也可以使用隱式轉換,但是往往顯示轉換更加安全一點,但是隱式轉換更加方便
- class Font{
- ...
- FontHandle get() const {return f;} //顯示轉換
- ...
- operator FontHandle() const {return f;} //隱式轉換函數(shù)
- ....
- private:
- FontHandle f; //管理的原始資源
- }
條款16:成對使用new和delete時要采用相同形式
不要對數(shù)組形式做typedef,因為這樣會導致delete的時候調用的是delete ptr而不是delete [] ptr,對內置類型會出現(xiàn)未定義或有害的,對類的類型會導致無法調用剩余的析構函數(shù),導致類中管理的資源無法釋放,從而造成內存泄漏 在new 表達式中使用[ ] ,則在相應的delete 表達式中也使用 [ ]
條款17:以獨立語句將newed對象置入智能指針
諸如這樣的語句processWidget (std::tr1::shared_ptr(new Widget),priority())
1. 在先執(zhí)行new Widget`語句和調用std::tr1::shared_ptr構造函數(shù)之間
2. 不能確定priority函數(shù)的執(zhí)行順序,可能在最前面,也可能在他們的中間
Part4四、設計與聲明
條款18:讓接口容易被正確使用,不易被誤用
我們接口應該替客戶著想,考慮周全,避免它們犯錯誤。例如在向函數(shù)傳遞日期的時候,把日期參數(shù)做成類的形式,并且用static成員函數(shù)來返回固定的月份,避免用戶參數(shù)寫錯 接口應該和內置接口保持一致,避免讓客戶感覺不舒服,這方面STL做的很好 tr1::shared_ptr支持定制型刪除器,使用它可以防范跨DLL構建和刪除的問題,可以用它來自動解除互斥鎖
條款19:設計class猶如設計type
謹慎的設計一個類,應該遵守以下規(guī)范
1. 合理的構建class的構造函數(shù)、析構函數(shù)和內存分配函數(shù)以及釋放函數(shù)
2. 不能把初始化和賦值搞混了
3. 如果你的類需要被用來以值傳遞,復制構造函數(shù)應該設計一個通過值傳遞的版本
4. 你應該給你的成員變量加約束條件,保證他們是合法值,所以你的成員函數(shù)必須擔負起錯誤檢查工作
5. 如果你是派生類,那么你應該遵守基類的一些規(guī)范,如析構函數(shù)是否為virtural
6. 你是否允許你的class有轉換函數(shù),,是否允許隱式轉換。如果你只允許explicit構造函數(shù)存在,就得寫出專門負責執(zhí)行轉換的函數(shù)
7. 想清楚你的類應該有哪些函數(shù)和成員
8. 哪些應該設計為私有
9. 哪個應該是你的friend,以及將他們嵌套與另一個是否合理
10. 對效率,異常安全性以及資源運用提供了哪些保證
11. 如果你定義的不是一個新type,而是定義整個type家族,那么你應該定義一個類模板
12. 如果只是定義新的字類以便為已有的類添加機制,說不定單純定義一個或多個non-member函數(shù)或模板更好
條款20:寧以pass-by-reference-to-const替換pass-by-value
盡量以pass-by-reference-to-const替換pass-by-value,因為前者通常比較高效,比如在含有類的傳遞時,避免了多次構造函數(shù)和多次析構函數(shù)的調用,大大的提高了效率 但是對于某些,比如內置類型,迭代器,函數(shù)調用等最好以值傳遞的形式
條款21:必須返回對象時,別妄想返回其reference
絕對不能返回指針或者一個引用指向一個臨時變量,因為它存在棧中,一旦函數(shù)調用結束返回那么你得到的將是一個壞指針,也不能使用static變量來解決,你可以通過返回值 來解決
條款22:將成員變量聲明為private
1. 為了保證一致性
2. 可以細微的劃分訪問和控制以及約束
3. 內部更改后不影響使用
protected并不比public更具封裝性
條款23:寧以non-member、non-friend、替換member函數(shù)
我們可以用non-member、non-friend函數(shù)來替換某些成員函數(shù),可以增加類的封裝性,包裹彈性和擴充性
條款24:若所有參數(shù)皆需要類型轉換,請為此采用non-member函數(shù)
如果你需要為某個函數(shù)的所有參數(shù)(包括被this指針所指的那個隱喻參數(shù))進行類型轉換,那么這個函數(shù)必須是個non-member
條款25:考慮寫出一個不拋出異常的swap函數(shù)
在你沒有定義swap函數(shù)的情況下,編譯器會為你調用通用的swap函數(shù),但是有的時候那并不是高效的,因為默認情況它在置換如指針的時候把整個內存都置換 我們采取一種解決辦法 1. 在類中提供一個 public swap成員函數(shù),并且這個函數(shù)不能拋出異常2. 在類的命名空間中提供一個non-member swap函數(shù),并令它調用類中的swap函數(shù) 3. 如果你正在編寫一個類而不是模板類,為你的class特化std::swap函數(shù),并令它調用你的swap函數(shù) 4. 請在類中聲明 using std::swap,讓其暴露,使得編譯器自行選擇更合適的版本
Part5五、實現(xiàn)
條款26:盡可能延后變量定義式的出現(xiàn)時間
定義一個變量,那么你就得承受這個變量的構造和析構的成本時間,所以在定義一個變量的時候我們應該盡可能的延后定義時間,在使用前定義,這樣避免我們定義了卻沒有使用它,造成浪費
條款27:盡量少做轉型動作
舊式轉型是C風格的轉型,C++中提供四種新式轉型:
- const_cast 通常被用來將對象的常量性轉除。它也是唯一有此能力的轉型操作符
- dynamic_cast 主要用來執(zhí)行“安全向下轉型” ,也就是用來決定對某對象是否歸屬繼承體系中的某個類型。它是唯一無法由舊式語法執(zhí)行的動作,也是唯一可能耗費重大運行成本的轉型動作
- reinterpret_cast 意圖執(zhí)行低級轉型,實際動作(及結果)可能取決于編譯器,這也就表示它不可移植。例如將一個pointer to int轉型為一個int。這一類轉型在低級代碼以外很少見。
- static_cast 用來強迫隱式轉換,例如將non-const對象轉換為const對象,或將int轉為double等等,它也可以用來執(zhí)行上述多種轉換的反向轉換,例如將void* 指針轉為 type 指針,將pointer-to-base 轉為 pointer-ro-derived 。但它無法將 const 轉為 non-const ——這個只有const_cast才能辦到
舊式轉型使用的時機是,當要調用一個explicit構造函數(shù)對一個對象傳遞給一個函數(shù)時,其他盡量用新式轉型
請記住以下:
1. 如果可以的話,避免dynamic_cast轉型,如果實在需要,則可以試著用別的無轉型方案代替
2. 如果轉型是必要的,那么應該把他隱藏于某個函數(shù)背后,客戶隨后可以調用該函數(shù),而不是需要將轉型放進自己的代碼里
3. 寧可要新型轉型,也不要使用舊式轉型
條款28:避免返回handles指向對象內部成分
避免返回handle(包括引用,指針和迭代器)指向對象內部。這樣可以增加封裝性,也能把出現(xiàn)空懸指針的可能性降低
條款29:為“異常安全”而努力是值得的
異常安全函數(shù)提供以下三個保證之一:基本承諾:如果異常被拋出,程序內的任何事物仍然保持在有效狀態(tài)下。沒有任何對象或數(shù)據(jù)會因此而敗壞,所有對象都處于一種內部前后一致的狀態(tài)。然而程序的現(xiàn)實狀態(tài)恐怕不可預料強烈保證:如果異常被拋出,程序狀態(tài)不改變。調用這樣的函數(shù)需要有這樣的認知:如果函數(shù)成功,就是完全成功,如果函數(shù)失敗,程序會恢復到“調用之前”的狀態(tài)不拋擲保證:承諾絕不拋出異常,因為它們總是能夠完成他們原先承諾的功能。作用于內置類型身上所有操作都提供nothrow保證,這是異常安全碼中一個必不可少的關鍵基礎材料
這三種保證是遞增的關系,但是如果我們實在做不到,那么可以提供第一個基本承諾,我們在寫的時候應該想如何讓它具備異常安全性
1. 首先以對象管理資源可以阻止資源泄漏
2. 在你能實現(xiàn)的情況下,盡量滿足以上的最高等級
條款30:透徹了解inlining 的里里外外
inline 聲明的兩種方式:
1. 隱喻的inline申請,即把定義寫在class內部
2. 明確聲明,即在定義式前加上關鍵字inline
將大多數(shù)inlining限制在小型、被頻繁調用的函數(shù)身上。這可使日后調試和二進制升級更容易,也可使得潛在的代碼膨脹問題最小化。不要只因為function templates出現(xiàn)在頭文件,就將他們聲明為inline
條款31:將文件間的編譯依存關系降至最低
支持“編譯依存性最小化”的思想是:相依于聲明式,不要相依于定義式
1. 頭文件和實現(xiàn)相分離,頭文件完全且僅有聲明式
2. 使用創(chuàng)建接口類
Part6六、繼承與面向對象設計
條款32:確定你的public繼承塑模出is-a關系
public繼承意味著is-a的關系,即子類是父類的一種特殊化,適合基類的一定適合子類,每個派生類對象含有著父類對象的特點
條款33:避免遮掩繼承而來的名稱
在父類中的名稱會被字類的名稱覆蓋,尤其是在public繼承下,沒有人希望這樣的發(fā)生 為了避免被遮掩,可以使用using聲明式或轉交函數(shù),交給子類
條款34:區(qū)分接口繼承和接口實現(xiàn)
聲明純虛函數(shù)的目的就是為了讓派生類只繼承函數(shù)接口 聲明虛函數(shù)的目的是讓派生類繼承該函數(shù)的接口和缺省實現(xiàn) 聲明普通函數(shù)的目的就是讓派生類強制接受自己的代碼,不希望重新定義
條款35:考慮virtual函數(shù)以外的其他選擇
條款36:絕不重新定義繼承而來的non-virtual函數(shù)
任何情況下都不應該重新定義一個繼承而來的non-virtual函數(shù)
條款37:絕不重新定義繼承而來的缺省參數(shù)值
絕對不要重新定義一個繼承而來的缺省參數(shù)值,因為缺省參數(shù)值都是靜態(tài)綁定的,而virtual函數(shù)——你唯一應該覆寫的東西是動態(tài)綁定
條款38:通過復合塑模has-a或“根據(jù)某物實現(xiàn)出”
區(qū)分public繼承和復合 在應用領域,復合意味著一個中含有另一個,即has-a關系;在實現(xiàn)領域意味著根據(jù)某物實現(xiàn)出
條款39:明智而審慎地使用private繼承
當需要復合時,盡可能的使用復合,必要時才使用private: 當protected成員或virtual函數(shù)牽扯進來的時候 當空間方面的利害關系,需要尺寸最小化
條款40:明智而審慎地使用多重繼承
多重繼承時候,如果其父類又繼承同一個父類,所以解決的方式就是使用virtual繼承,即其父類同時以virtual繼承那個父類,但是相應的也會付出一些代價,例如時間更慢,需要重新定義父類的初始化等,因此設計時最好不要讓這個父類有任何數(shù)據(jù)成員當單一繼承和多重繼承都可以,那么最好選擇單一繼承,多重繼承也有正當?shù)挠猛荆梢詫崿F(xiàn)同時public繼承和private繼承的組合
Part7七、模板與泛型編程
條款41:了解隱式接口和編譯期多態(tài)
顯式接口:由函數(shù)的簽名式(也就是函數(shù)名稱、參數(shù)類型、返回類型)構成 隱式接口:不基于函數(shù)簽名式,而是由有效表達式組成 面向對象和泛型編程都支持接口和多態(tài),只不過一個以顯式為主,一個以隱式為主 兩種多態(tài)一個在運行期一個在編譯期
條款42:了解typename的雙重意義
聲明模板參數(shù)的時候,class和typename是可以互換的,沒什么不一樣 但是標識嵌套從屬類型名稱的時候必須用typename 不得在基類列(繼承的時候)或成員初值列(初始化列表)內以它作為基類修飾符
- templete<typename T>
- class Derived:public Base<T>::Nested{ //基類列表中不可以加“typename”
- public:
- explicit Derived(int x): Base<T>::Nested(x){//mem.init.list中不允許“typename”
- typename Base<T>::Nested temp; //這個是嵌套從屬類型名稱
- ... //作為一個基類修飾符需要加上typename
- }
- }
條款43:學習處理模板化基類內的名稱
模板化基類指的是當派生類的基類是一個模板
1. 在基類函數(shù)調用之前加上 this->
2. 使用 using 聲明式 ,告訴編譯器,請它假設這個函數(shù)存在
3. 指出這個函數(shù)在基類中,使用基類::函數(shù)的形式寫出來(不推薦這個,因為如果是virtual函數(shù),則 會影響動態(tài)綁定)
但是當有模板全特化的時候,確實使用的沒有這個函數(shù),那么依然會報錯
條款44:將與參數(shù)無關的代碼抽離出來
模板生成多個類和多個函數(shù),所以任何模板代碼都不該和某個造成膨脹的模板參數(shù)產生相依關系 因非類型模板參數(shù)造成的代碼膨脹,往往可以消除,做法是以函數(shù)參數(shù)或類成員變量替換模板參數(shù) 因類型模板參數(shù)造成的代碼膨脹,往往可以降低,做法是讓帶有完全相同的二進制表述 的具體類型共享實現(xiàn)碼
條款45:運用成員函數(shù)模板接受所有兼容類型
使用成員函數(shù)模板可以生成接收所有兼容類型的函數(shù) 如果你聲明成員函數(shù)模板用來泛化拷貝構造函數(shù)和賦值操作,那么你還需要聲明正常的拷貝構造函數(shù)和賦值操作
條款46:需要類型轉換時請為模板定義非成員函數(shù)
當我們編寫一個模板類,它提供的和這個模板祥光的函數(shù)支持所有參數(shù)的隱式類型轉換,請將哪些函數(shù)定義為模板類的內部的friend函數(shù)
Part8八、定制new和delete
條款49:了解new—handler的行為
當new分配失敗的時候,它會先調用一個客戶指定的錯誤處理函數(shù)(set_new_handler),一個所謂的new—handler 它是一個typedef定義出一個指針指向函數(shù),該函數(shù)沒有參數(shù)也不返回任何東西 set_new_handler的參數(shù)是個指針指向operator new 無法分配足夠內存時該被調用的函數(shù)。其返回值也是個指針,指向set_new_handler 被調用前正在執(zhí)行(馬上就要被替換)的那個new—handler函數(shù) 一個良好設計的new—handler函數(shù)必須做以下事情:
1. 讓更多內存可被使用。此策略的一個做法是,程序一開始就分配一大塊內存,而后當其第一次被調用,將它釋還給程序使用
2. 安裝另一個new—handler。可以設置讓其調用另一個new—handler來替換自己,用來做不同的事情,其做法是調用set_new_handler
3. 卸載new—handler,也就是將null指針傳給set_new_handler,這樣new在分配不成功時拋出異常
4. 拋出bad_alloc的異常。
5. 不返回,調用abort或exit
6. C++并部支持類的專屬new—handler,但其實也不需要。你可以令每個類提供自己的set_new_handler和operator new即可
set_new_handler允許客戶指定一個函數(shù),在內存分配無法獲得滿足時調用。
Nothrow new是一個頗為局限的工具,因為它只適用于內存分配:后繼的構造函數(shù)調用還是可能拋出異常
條款50:了解new和delete的合理替換時機
替換operator new或operator delete的三個常見理由:用來檢測運用上的錯誤 為了收集使用上的統(tǒng)計數(shù)據(jù) 為了增加分配和歸還的速度 為了降低缺省內存管理器帶來的空間額外開銷,也就是實現(xiàn)內存池,可以節(jié)省空間為了彌補缺省分配器中的非最佳齊位 為了將相關對象成簇集中 為了獲得非傳統(tǒng)行為
了解何時可在“全局性的”或“class專屬的”基礎上合理替換缺省的new和delete
條款51:編寫new和delete時需固守常規(guī)
operator new應該內含有一個無窮的循環(huán),并在其中嘗試分配內存,如果它無法滿足內存需求,就該調用new-handler。它也應該有能力處理0 bytes申請,即將其按照1 byte分配。Class 專屬版本應該處理“比正確大小更大的(錯誤)申請”,因為當有字類繼承的時候,會出現(xiàn)傳入的大小和父類大小不同,所以要進行判斷形如if(size != sizeof(父類))operator delete應該在收到NULL指針的時候什么也不做,必要時交給全局的operator new來處理。
條款52:寫了placement new也要寫placement delete
當你寫一個placement operator new ,請確定也寫了對應的placement operator delete版本。如果沒有這樣做,可能回發(fā)生隱微而時斷時續(xù)的內存泄露當你聲明placement new 和placement delete,請確定不要無意識(非故意)地遮掩正常的全局版本,你如果想提供自定義形式,請內含所有正常形式的new和delete或利用繼承機制及using聲明式
Part9九、雜項討論
條款53:不要輕忽編譯器的警告
不同的編譯器有不同的警告標準,要嚴肅對待編譯器發(fā)出的警告信息。努力在你的編譯器的最高警告級別下爭取“無任何警告”的榮譽 不要過度依賴編譯器的報警能力,因為不同的編譯器對待事情的態(tài)度并不相同。一旦移植到另一個編譯器上,你原本依賴的警告信息有可能消失
條款54:讓自己熟悉包括TR1在內的標準程序庫
C++標準程序庫的主要機能由STL、iostream、locales組成。并包含C99標準程序庫。TR1添加了智能指針(例如 tr1::shared_ptr)、一般化函數(shù)指針(tr1::function)、hash-based容器、正則表達式以及另外10個組件的支持 TR1自身知識一份規(guī)范。為了獲得TR1提供的好處,你需要一份實物。一個好的實物來源是Boost。
條款55:讓自己熟悉Boost
Boost是一個社群,也是一個網站。致力于免費、源碼開放、同僚復審的C++程序庫開發(fā)。Boost在C++標準化過程中扮演具有影響力的角色 Boost提供許多TR1組件實現(xiàn)品,以及其他許多程序庫
原文地址:https://mp.weixin.qq.com/s/JUZtEgarDq15ToVIRHsjaw