麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學院 > 開發設計 > 正文

effect經典總結

2019-11-14 09:26:55
字體:
來源:轉載
供稿:網友

1,C++屬于一個語言聯邦 : C     Object-Oriented C++     Template C++       STL

2,應盡量以const,enum,inline替換#define

  如果一個常量是class專屬常量又是static,且為整數類型(int,char,bool),則需特殊處理:只要不取它們的地址,可以聲明并使用它們而不須提供定義式。

但是如果取某個class專屬常量的地址,或縱使不取其地址而編譯器卻(不正確的)堅持要看到一個定義式,必須提供定義式

enum的行為某方面比較像#define而不像const:取一個const地址合法,但是取一個enum地址就不合法,而取#define也不合法,如果不想讓被人獲得一個pointer或reference指向你的某個整數常量,enum可以幫助你實現這個約束

#define和enum不會設定額外的空間,const在優秀的編譯器中也許可能也是這樣,但是不夠優秀的編譯器就必須設定額外的空間

3,盡可能使用const

const語法雖然變化多端,但并不莫測高深。如果關鍵字const出現在*左側,表示被指物是常量;如果出現在*右邊,表示指針自身是常量;如果出現在*兩邊,表示被指物和指針都是常量

std::vector<int>  vec;

const std::vector<int>::interator  iter = vec.begin()                    T*const

std::vector<int>:const_iterator iter = vec.begin()                       const T*

 

將const實施于成員函數的目的,是為了確認該成員函數可作用于const對象身上

const特性的兩個函數可以重載(必須在類中,不在類中會出現問題) const函數不可改變對象任何變量(注意區分指針的情況,只要指針不變,指向的值可變化)

注意操作符[]的重載要返回值的引用,否則不能對結果賦值(相當于對值的一個拷貝賦值,沒有意義)

mutable可以在常函數中修改其值,但是一般作用是:1,用于緩存2,或必須在常函數中修改值

 

利用const Operator[]實現出non-const版本:

class TextBlock {

public:

           const char & operator[](std::size_t position) const {  .....               return text[position]; }

           char & operator[](std::size_t position){

                  return  const_cast<char &>(  static_cast<const  TextBlock&> (*this)[position]);

};

 

非const調用const是安全的

const調用非const是不安全的,(因為非const有可能改變)

總結:

      1>將某些東西聲明為const可幫助編譯器偵測出錯誤用法。const可被施加于任何作用域內的對象、函數參數、函數返回類型、成員函數本體

      2>編譯器強制實施bitwise constness,但你編寫程序時應該使用“概念上的常量性”(conceptual constness)

      3>當const和non-const成員函數有著實質等價的實現時,令non-const版本調用const版本可避免代碼重復

4,確定對象被使用之前已被初始化:

為了保證一定性,使用內建數據類型一定要初始化,構造對象要保證構造函數初始化它的成員

C++ 對“定義在不同的編譯單元內的non-local  static對象”的初始化相對次序并無明確定義。因為決定它們初始化次序相當困難,根本無解

最常用的形式,就是  多個編譯單元內的non-local static對象經由“模板隱式具體化,implicit template instantiations"形式(而后者自己可能也是經由”模板隱式具現化“形成)

 

任何一種non-const static對象,不論它是local或non-local,在多線程環境下“等待某事發生”都會有麻煩。處理方法:在程序的單線程啟動階段手工調用所有的reference-returning函數,這可消除與初始化有關的“競速形勢”

 

為了避免在對象初始化之前過早地使用它們,你需要做三件事:

第一,手工初始化內置型non-member對象。

第二,使用成員初值列對付對象的所有成分

第三,在”初始化次序不缺定性“(這對不同編譯單元所定義的non-local static對象是一種折磨)氛圍下加強設計

 

總結:

            1>為內置對象進行手工初始化,因為C++不保證初始化它們

            2>構造函數最好使用成員初始化列表,而不要在構造函數體內使用賦值操作。次序和變量聲明的順序一致

            3>為免除“跨編譯單元之初始化次序”問題,請以local  static對象替換non-local static對象

5,編譯器默認提供四個public且inline函數,賦值,拷貝,構造,析構,但是它們是在需要的時候才被編譯器創建出來的

C++不允許讓引用改指向不同的對象

>如果打算在一個“內含reference成員”的class內支持賦值操作,必須自己定義copy assignment操作符

>如果某個base class將copy assignment操作符聲明為PRivate,編譯器將拒絕為其derived classes 生成copy assignment操作符

 

6,若不想使用編譯器自動生成的函數,就該明確拒絕:將他們聲明為private,同時不要實現他們,這樣的話即使friend或者成員函數調用他們連接器會提示錯誤

另外一種方法是把他們聲明為private在一個單獨的類中,然后用這個類繼承它

7,為多態基類聲明virtual析構函數

>帶有多態性質的base classes應該聲明一個virtual析構函數。如果class帶有任何virtual函數,他就應該擁有一個virtual析構函數

>classes的設計目的如果不是作為base classes使用,或不是為了具備多態性,就不該聲明virtual析構函數

8,別讓異常逃離析構函數

>析構函數絕對不要吐出異常。如果一個被析構函數調用的函數可能拋出異常,析構函數應該捕捉任何異常,然后吞下它們(不傳播)或結束程序

>如果客戶需要對某個操作函數運行期間拋出異常作出反應,那么class應該提供一個普通函數(而非在析構函數中)執行該操作

9,絕不在構造和析構過程中調用virtual函數

>無法使用virtual函數從base classes向下調用,在構造期間,可以藉由“令derived classes將必要的構造信息向上傳遞到base class構造函數”替換加以彌補

>在構造和析構期間不要調用virtual函數,因為這類調用從不下降至derived class(比起當前執行構造函數和析構函數的那層)

10,令operator=返回一個 reference to *this

                                                  目的是:為了實現“連鎖賦值”

11,在operator=中處理“自我賦值”

自我賦值     發生在對象被賦值給自己時

>確保當對象自我賦值時operator=有良好行為。其中技術包括比較“來源對象”和“目標對象”的地址、精心周到的語句順序、以及copy-and-swap

>確定任何函數如果操作一個以上的對象,而其中多個對象是同一對象時,其行為仍然正確

12,復制對象時勿忘其每一個成分

自己編寫copying函數,要確保:

1,復制所有local成員變量

2,調用所有base classes內的適當copying函數

 

>Copying函數應該確保復制“對象內的所有成員變量”及“所有base class成分”

>不要嘗試以某個copying函數實現另一個copying函數。應該將共同機能放進第三個函數中,并由兩個copying函數共同調用

 

所謂資源就是:一旦用了它,將來必須還給系統,否則會出現問題。C++最常用的資源就是動態內存分配,當然還有其他資源:文件描述扶,互斥鎖,圖形界面中的字型和筆刷、數據庫連接、以及網絡sockets

13,以對象管理資源

兩個關鍵想法:

>獲得資源后立刻放進管理對象內

>管理對象運用析構函數確保資源被釋放

 

由于auto_ptr被銷毀時會自動刪除它所指之物,所以一定要注意別讓多個auto_ptr同時指向同一對象。如果真是那樣,對象會被刪除一次以上,而那會使你的程序搭上駛向“未定義行為”的快速列車上。為了預防這個問題,auto_ptr有一個不尋常的性質:若通過copy構造函數或copy assignment操作符復制它們,它們會變成null,而復制所得的指針將取的資源的唯一控制權?。。。ㄔ撔再|有利也有弊)

 

auto_ptr的替代方案是“引用計數型智慧指針”(RCSP),RCSP也是個智能指針,持續追蹤共有多少對象指向某筆資源,并在無人指向它時自動刪除該資源。RCSP提供的行為類似垃圾回收,不同的是RCSP無法打破環狀引用:::tr1:shared_ptr就是一個RCSP

 

注意:auto_ptr和tr1::shared_ptr兩者都在析構函數內做delete而不是delete[]動作??!如果對數組指針調用則是餿主意

 

>為了防止資源泄漏,請使用RAII對象,它們在構造函數中活得資源并在析構函數中釋放資源 (Resource Acquisition Is Initialization,RAII)

>兩個常被使用的RAII  classes分別是tr1::shared_ptr和auto_ptr。前者通常是較佳選擇,已經其copy行為比較直觀。若選擇auto_ptr,復制動作會時它(被復制物)指向null

14,在資源管理類中小心copying行為

在RAII中當一個對象被復制時,出現嚴重后果,一般有兩種方案:

>禁止復制(聲明為private)

>對底層資源祭出“引用計數法”(reference-count)           這種做法一般如果內含有一個tr1::shared_ptr ,但是默認事件是count為0時刪除,幸運的是我們可以自己指定為0時的事件

 

類的析構函數會自動調用其non-static成員變量的析構函數

復制底部資源                             (深度拷貝)

轉移底部資源的擁有權              (auto_ptr)

 

15,在資源管理類中提供對原始資源的訪問

tr1::shared_ptr和auto_ptr都提供了一個get函數,用來執行顯式轉換,也就是它返回智能指針內部的原始指針,以便于直接訪問時可以通過

它們還重載了(->和*)操作符

 

>APIs往往要求訪問原始資源(raw resources),所以每一個RAII class應該提供一個“取得其所管理之資源”的辦法

>對原始資源的訪問可能經由顯式轉換或隱式轉換。一般而言顯式轉換比較安全,但隱式轉換對客戶比較方便

 

16,成對使用new和delete時要采用相同形式

           最好不要用typedef,否則會造成語義不清:

         typedef  std::string AddressLines[4];

         std::string  *pal = new AddressLines;

         delete pal;          錯誤?。?!

         delete[] pal ;       正確?。?!

17,以獨立語句將newed對象置入智能指針

>      以獨立語句將newed對象存儲于(置入)智能指針內。如果不這樣做,一旦異常被拋出,有可能導致難以覺察的資源泄露

 

18,讓接口容易被正確使用,不易被誤用

>好的接口很容易被正確的使用,不容易被誤用。應該在所有的接口中努力達成這些性質

>“促進正確使用”的辦法包括接口一致性,以及與內置類型的行為兼容

>“組織誤用”的辦法包括建立新類型、限制類型上的操作,束縛對象值,以及消除客戶的資源管理責任

>tr1::shared_ptr支持定制型刪除器。這個防范DLL問題,可被用來自動解除互斥鎖等等

 

19,設計class猶如設計type

好的types是一項艱巨的工作。好的types有自然的語法,直觀的語義,以及一或多個高效的實現品

如何設計好的classes:

>新的type的對象應該如何被創建和銷毀

>對象的初始化和對象的賦值該有什么差別

>新的type的對象如果被passed by value(以值傳遞),意味著什么

>什么是新type的“合法值”

>新的type需要配合某個繼承圖系么

>新的type需要什么樣的轉換

>什么樣的操作符和函數對此新type而言是合理的

>什么樣的標準函數應該駁回

>誰該取用新type的成員

>什么是新type的“未聲明接口”

>新type有多么一般化

>真的需要一個新type么

 

20,寧以pass-by-reference-to-const替換pass-by-value

>盡量以pass-by-reference-to-const替換pass-by-value。前者通常比較高效,并可避免切割問題

>以上規則并不適用于內置類型,以及STL的迭代器和函數對象。對它們而言,pass-by-value往往比較適當

 

21,必須返回對象時,別妄想返回其reference

任何時候看到一個reference聲明式,都應該立刻問自己,它的另一個名稱是什么?因為它一定是某物的另一個名稱

任何函數如果返回一個reference指向某個local對象,都將一敗糊涂

>絕不要返回point或reference指向一個local stack對象,或返回reference指向一個heap-allocated對象,或返回pointer或reference指向一個local static對象而有可能同時需要多個這樣的對象

 

22,將成員變量聲明為private

>切記將成員函數聲明為private。這可賦予客戶訪問數據的一致性、可細微劃分訪問控制、允許約束條件獲得保證,并提供class作者以充分的實現彈性

>protected并不比public更具封裝性

 

23,寧以non-menber、non-friend替換menber函數

這樣做可以增加封裝性、包裹彈性和機能擴充性

 

24,若所有參數皆需要類型轉換,請為此采用non-member函數

>如果需要為某個函數的所有參數(包括被this指針所指的那個隱喻參數)進行類型轉換,那么這個函數必須是個non-member

 

25,考慮一個不拋出異常的swap函數

 pimpl手法    :point to implementation

C++只允許對class template偏特化,在function templates身上偏特化行不通,解決方案是:為它添加一個重載版本

>當std::swap對你的類型效率不高時,提供一個swap成員函數,并確定 這個函數不拋出異常

>如果你提供一個member swap,也該提供一個non-member swap用來調用前者。對于classes(而非templates),也請特化std::swap

>調用swap時應針對std::swap使用using聲明式,然后調用swap并且不帶任何“命名空間資格修飾”

>為“用戶定義類型”進行std  template全特化是好的,但千萬不要嘗試在std內加入某些對std而言全新的東西

 

26,盡可能延后變量定義式的出現時間

 >盡可能延后變量定義式的出現。這樣做可增加程序的清晰度并改善程序的效率。

 

27,盡量少做轉型動作

>const_cast通常被用來將對象的常量性轉除。它也是唯一有此能力的C++-style轉型操作符

>dynamic_cast主要用來執行“安全向下轉型”,也就是用來決定某對象是否歸屬繼承體系中的某個對象。它是唯一無法由舊式語法執行的動作,也是唯一可能耗費重大運行成本的轉型動作

>reinterpret_cast意圖執行低級轉型,實際動作(及結果)可能取決于編譯器,這也就是表示它不可移植。例如將point to int轉型為int

>static_cast用來強迫飲食轉換。例如將non-const轉型const對象,或將int轉型double等等。但是無法將const轉型non-const

 

任何一個類型轉換(不論是通過轉型操作而進行的顯式轉換,或通過編譯器完成的隱式轉換)往往真的令編譯器編譯出運行期執行的碼

 

單一對象(例如Derived對象)可能擁有一個以上的地址(例如“以base *指向它”時的地址和“以Derived *指向它”時的地址)行為

之所以需要dynamic_cast,通常是因為想在一個認定為derived對象身上執行derived class操作函數,但手上卻只有一個"指向base”的pointer或reference,只能靠它們呢來處理對象

絕對必須避免的一件事是所謂的"連串 dynamic_casts"

 

>如果可以,盡量避免轉型,特別是在注重效率的代碼中避免dynamic_casts。如果有個設計需要轉型這個動作,試著發展無需轉型的替代品

>如果轉型是必要的,試著將它隱藏于某個函數背后??蛻綦S后可以調用該函數,而不需要將轉型放進他們自己的代碼內

>寧可使用C++-style轉型,不要使用舊式轉型。前者容易辨識出來,而且也比較有著分門別類的職掌

 

28,避免返回handles指向對象內部成分

 兩個教訓:

          --->成員變量的封裝性最多只等于"返回其reference"的函數的訪問級別

          --->如果const成員函數傳出一個reference,后者所指數據與對象自身關聯,而它又被存儲于對象之外,那么這個函數的調用者可以修改那筆數據

handles: 指針,reference,迭代器

避免返回handles(reference,pointer,iterator)指向對象內部。遵守這個約定可增加封裝性,幫助const成員函數的行為像個const,并將發生”虛吊號碼牌“(dangling handles)的可能性降到最低

 

29,為"異常安全"而努力是值得的

當異常被拋出時,帶有異常安全性的函數會:

=>不泄露任何資源

=>不允許數據敗壞

 

異常安全函數提供以下三個保證之一:

==>基本承諾

==>強烈保證

==>不拋擲保證

1,> 異常安全函數(Exception-safe functions)即使發生異常也不會泄露資源或允許任何數據結構敗壞。這樣的函數區分三種可能的保證:基本型,強烈型,不拋異常型

2,>“強烈保證"往往能夠以copy-and-swap實現出來,但"強烈保證"并非對所有函數都可實現或具備實現意義

3,>函數提供的"異常安全保證"通常最高只等于其所調用之各個函數的"異常安全保證"中的最弱者

30,透徹了解inlining的里里外外

inline只是對編譯器的一個申請,不是強制命令

inline函數通常 一定 被置于頭文件內

inline 在大多數C++程序中時編譯器行為,只有少數基于.NET CLI(Common Language Infrastructure,公共語言基礎設施)可以在運行期完成inlining

Template通常也被置于頭文件中,以為一旦被使用,編譯器為了將它具現化,需要知道它長什么樣子(像inline),(并不是同一準則,某些建置環境可以在連接期執行template具現化)

編譯器拒絕將過于復雜的函數(循環或遞歸)的函數inlining。而所有對virtual函數的調用(除非最平淡無奇的)也對會使inling落空,因為virtual是運行期確定

編譯器通常不對“通過函數指針而進行的調用”實施inlining,因為要確定地址

inline函數無法升級

很多調試器對inline函數束手無策

 

>將大多數inlining限制在小型、被頻繁調用的函數身上。這可使日后的調試過程和二進制升級更容易,也可使潛在的代碼膨脹問題最小化,使程序的速度提升機會最大化

>不要只因為function templates出現在頭文件,就將它們聲明為inline

 

31,將文件間的編譯依存關系降至最低

如果使用object references 或 object pointers可以完成任務,就不要使用objects

如果能夠,盡量以class聲明替換class定義式

為聲明式和定義式提供不同的頭文件

>支持“編譯依存性最小化”的一般構想是:相依于聲明式,不要 相依于定義式。基于此構想的兩個手段是Handle classes和Interface classes

>程序庫頭文件應該以“完全且僅有聲明式”的形式存在。這種做法不論是否涉及templates都適用

 

繼承與面向對象

 

32,確定public繼承塑模出is-a關系

以C++進行面向對象編程,最要的一個原則:公開繼承 意味 "is-a“的關系

企鵝是一種鳥,但企鵝不會飛 理論解決辦法:1,雙繼承  2,重新(一個錯誤的)飛功能  3,都不寫飛功能

 

>"public"繼承意味著is-a。適用于base classes身上的每一件事情一定也適用于derived classes身上,因為每一個derived class對象也都是一個

base class對象

 

33,避免遮掩繼承而來的名稱

 

復制代碼
 1 #include <iostream> 2 using namespace std; 3  4 class Base { 5 private: 6     int x; 7 public: 8     virtual void mf1() = 0; 9     virtual void mf1(int);10     virtual void mf2();11     void mf3();12     void mf3(double);13 };14 15 class Derived : public Base {16 public:17     virtual void mf1();18     void mf3();19     void mf4();20 };21 22 int main()23 {24     Derived d;25     int x;26 27     d.mf1();   //Derived::mf128     d.mf1(x);  //ERROR !!!  NO ARGS              using Base::mf129     d.mf2();   //Base::mf230     d.mf3();   //Derived::mf331     d.mf3(x);  //ERROR !!! NO ARGS               using Base::mf332 33     return 0;34 }復制代碼

 

 

 

 上面的程序只是為了說明編譯時候的正確性,因此有些函數沒有實現,鏈接肯定通不過,不過能說明問題

 

>derived classes內的名稱會遮掩base classes內的名稱。在public繼承下從來沒有人希望如此

>為了讓被遮掩的名稱再見天日,可使用using聲明式或轉交函數

 

34,區分接口繼承和實現繼承

 聲明一個pure virtual函數的目的是為了讓derived classes只繼承函數接口

 聲明簡樸的(非純)impure virtual函數的目的,是讓derived classes繼承該函數的接口和缺省實現

 聲明non-virtual函數的目的是為了令derived classes繼承函數的接口及一份強制性實現

 一個典型的程序有80%的執行時間花費在%20的代碼身上

>接口繼承和實現繼承不同。在public繼承之下,derived classes總是繼承base class的接口

>pure virtual函數只具體指定接口繼承

>簡樸的(非純)impure virtual函數具體指定接口繼承及缺省實現繼承

 

>non-virtual函數具體指定接口繼承以及強制性實現繼承

 

35,考慮virutal 函數以外的其他選擇

>virtual函數的替代方案包括NVI手法及Stratrgy設計模式的多種形式。NVI手法自身是一個特殊形式的Template Method設計模式

>將機能從成員函數移到class外部函數,帶來的一個缺點是,非成員函數無法訪問class的non-public成員

>tr1::function對象的行為就像一般函數指針。這樣的對象可接納“與給定值目標簽名兼容”的所有可調用物

 

36,絕不重新定義繼承而來的non-virtual函數

>絕對不要重新定義繼承而來的non-virtual

 

37,絕不重新定義繼承而來的缺省參數值

virtual函數系動態綁定,而缺省參數值卻是靜態綁定

>絕對不要重新定義一個繼承而來的缺省參數值,因為缺省參數值都是靜態綁定,而virtual函數—你唯一應該覆寫的東西——確實動態綁定

 

38,通過復合塑模出has-a或“根據某物實現出”

>復合的意義和public繼承完全不同

>在應用域,復合意味has-a。在實現域,復合意味is-implemented-in-terms-of(根據某物實現出)

 

39,明智而審慎的使用private繼承

private繼承主要用于“當一個意欲成為derived class者想訪問一個意欲成為base class者的protected成分,或為了重新定義一或多個virtual函數

EBO  empty base optimization 空白基類最優化,只適用于單一繼承

復合和private繼承都意味 is-implemented-in-terms-of

>Private 繼承意味is-implemented-in-terms-of(根據某物實現出)。它通常比復合的級別低。但是當derived class需要訪問protected base class的成員,或需要重新定義繼承而來的virtual函數時,這么設計是合理的

>和復合不同,private繼承可以造成empty base最優化。這對致力于“對象尺寸最小化”的程序庫開發者而言,可能很重要

 

40,明智而審慎的使用多重繼承

C++編譯器解析重載函數調用的規則:在看到是否有個函數可取用之前,C++首先確認這個函數對此調用的最佳匹配。找出最佳匹配函數后才檢驗其可取用性

virtual base的初始化責任是由繼承體系中的最低層class 負責。這暗示:

1>classes若派生自virtual bases而需要初始化,必須認知其virtual bases——不論那些bases距離多遠

2>當一個新的derived class加入繼承體系中,它必須承擔起virtual bases(不論直接還是間接)的初始化責任

對待virtual base classes: 1,非必須不是有2,如果必須使用,盡可能避免在其中放置數據

 

>多重繼承比單一繼承復雜。它可能導致新的歧義性,以及對virtual繼承的需要

>virtual繼承會增加大小,速度,初始化(及賦值)復雜度等等成本。如果virtual base classes不帶任何數據,將是最具實用價值的情況

>多重繼承的確有正當用途。其中一個情節涉及"public繼承某個Interface class"和"private 繼承某個協助實現的class"的兩相組合

 

41,了解隱式接口和編譯期多態

Templates及泛型編程的世界,與面向對象有根本的不同。在此世界中顯式接口和編譯期多態依然存在,但重要性降低。反倒是隱式接口和編譯期多態移到前面了

>classes和templates都支持接口和多態

>對classes而言接口是顯式的,以函數簽名為中心。多態則是通過virtual函數發生于運行期

>對template參數而言,接口是隱式的,奠基于有效表達式。多態則是通過template具現化和函數重載解析發生于編譯期

 

42,了解typename的雙重意義

template內出現的名稱如果相依于某個template參數,稱之為從屬名稱

如果C++解析器在template中遭遇一個嵌套從屬名稱,它便假設這個名稱不是個類型,除非告訴它是(typename)

typename不可以出現在base classes list內的嵌套從屬類型名稱之前,也不可以在member initialization list中作為base class修飾符

>聲明template參數時,前綴關鍵字class和typename可互換

>請使用關鍵字typename標識嵌套從屬類型名稱;但不得在base class list(基類列)或member initialization list內以它作為base class修飾符

 

43, 學習處理模板化基類內的名稱

class 定義式最前面的"template<>"語法象征這既不是template也不是標準的class 。而是模板全特化

C++編譯期往往拒絕在templatized base classes(模板化基類)內尋找繼承而來的名稱,因為有可能特化而擁有不同的接口!可這是個嚴重的問題,我們可以有三個辦法解決:

1,在調用base class函數動作之前加上this->

2, 使用using聲明式

3, 明白指出被調用函數位于base class內,但是如果是虛函數的話會導致關閉虛函數"virtual 綁定行為"

 

>可在derived class tempalte內通過"this->"指涉base class templates內的成員名稱,或藉由一個明白的"base class資格修飾符"完成

 

44, 將于參數無關的代碼抽離templates

>Template生成多個classses和多個函數,所以任何template代碼都不該與某個構造成膨脹的template參數產生相依關系

>因非類型模板參數而造成的代碼膨脹,往往可消除,做法是以函數參數或class成員變量替換template參數

>因類型參數而造成的代碼膨脹,往往可降低,做法是讓帶有完全相同二進制表述的具現類型共享實現碼

 

45,運用成員函數模板接受所有兼容類型

>請使用member function templates生成"可接受所有兼容類型"的函數

>如果你聲明member templates用于"泛化copy構造"或"飯或assignment操作",你還是需要聲明正常的copy構造函數和copy assignment操作符

 

46, 需要類型轉換時請為模板定義非成員函數

在template實參推導過程中從不將隱式類型轉換函數納入考慮

>當我們編寫一個class template,而它所提供之"與此template相關的"函數支持"所有參數之隱式類型轉換"時,請將那些函數定義為"class template內部的friend函數"

 

47, 請使用traits classes表現類型信息

>Traits classes使得"類型相關信息"在編譯期可用。它們以templates和"templates特化"完成實現

>整合重載技術后,traits classes有可能在編譯期對類型執行if ... else 測試

 

48, 認識template元編程

 

復制代碼
 1 #include <iostream> 2  3 template<unsigned n> 4 struct Factorial 5 { 6     enum { value = n * Factorial<n-1>::value}; 7 }; 8  9 template<>10 struct Factorial<0> {11     enum { value = 1 };12 };13 14 15 int main(int argc,char *argv[])16 {17     std::cout << Factorial<5>::value << std::endl;18     std::cout << Factorial<10>::value << std::endl;19 20     return 0;21 }復制代碼

 

好處:1,確保量度單位正確 2,優化矩陣 3, 可以生成客戶定制之設計模式

 

>Template metaprograming可將工作由運行期移往編譯期,因而得以實現早期錯誤偵測和更高的執行效率

>TMP可被用來生成"基于政策選擇組合"的客戶定制代碼,也可用來避免生成對某些特殊類型不適合的代碼

 

49,了解new-handler的行為

new-handler函數必須做以下事情:

1= 讓更多內存可被使用

2= 安裝另一個new-handler

3= 卸除new-handler

4= 拋出bad_alloc(或派生自bad_alloc)的異常

5= 不返回

 

operator new要做以下事情:

1= 調用set_new_handler,告知Widget的錯誤處理函數。這會將class的new-handler安裝為global new-handler

2= 調用global operator new,執行實際之內存分配。如果分配失敗,global operator new會調用class的new-handler,因為那個函數才剛被安裝為global new-handler。如果global operator new最終無法分配足夠內存,會拋出一個bad_alloc異常。在此情況下class的operator new必須恢復原來的global new-handler,然后再傳播該異常。為確保原來的new-handler總是能夠被重新安裝回去,class將global new-handler視為資源并遵守忠告,運用資源管理對象防止資源泄漏

3= 如果global operator new能夠分配足夠一個class對象所用的內存,class的operator new會返回一個指針,指向分配所得。class析構函數會管理golbal new-handler,它會自動將class ‘s operator new被調用前的那個global new-handler恢復回來

 

50,了解new和delete的合理替換機制

51,編寫new和delete時需固守常規

52,寫placement new 也要寫 placement delete

53,不要輕易忽略編譯期警告

54,讓自己熟悉包括TR1在內的標準程序庫

55,讓自己熟悉Boost

有一種落差是,你配不上自己的野心,也辜負了所受的苦難
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 日本免费aaa观看 | 毛片在线免费播放 | 欧美一区二区黄色 | 久久久久久久久国产 | 亚洲二区不卡 | 欧美日韩在线播放 | 欧美精品成人一区二区在线观看 | 亚洲成人在线免费 | 黄色毛片视频在线观看 | 国产日韩线路一线路二 | 久久国产免费视频 | 可以看逼的视频 | 国产69精品久久久久久久久久 | 毛片免费观看视频 | 国产一国产一级毛片视频 | 久久草在线观看视频 | 国产精品久久久久网站 | 亚洲av一级毛片特黄大片 | 射逼网站 | 国产精品一区二区三区99 | 色就操| 国产无限资源在线观看 | av成人在线免费观看 | 一级国产航空美女毛片内谢 | 精品在线观看一区 | 日韩大片在线永久观看视频网站免费 | 麻豆传传媒久久久爱 | www.9191.com| mmmwww| 欧美一区2区三区4区公司二百 | 草草免费视频 | chinesehdxxxx无套| 在线日韩亚洲 | 欧美女同hd | 欧美一级性| 国产精品久久久久av | 久久国产精品91 | 成人aaaaa片毛片按摩 | wwwxxx国产 | 国产精品久久久久久久亚洲按摩 | 一区二区网|