青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆-19  評論-2  文章-0  trackbacks-0

========================
Effective C++   實現
書作者:Scott Meyers
原筆記作者:Justin
========================

Item 26 : 盡可能延后變量定義式的出現時間
--------------------------------------------------
 tag:
 ·盡可能延后變量定義式的出現,以增加程序的清晰度并改善程序效率。
 
 定義變量包含了該變量對象的構造操作,如果因為某個原因(如拋出異常,條件語句未執行等)而沒有真正用到這個變量,那么構造該變量所耗費的時間和資源就白費了。
 在即將使用變量前再定義它對理解代碼也有好處:要想知道某個變量時做什么用的?讀接下來的代碼便是。

 思考題,以及答案:
 //方法A:循環外定義
 Widget w;
 for (int i = 0; i < n; ++i){
    w = some_value_dependent_on_i;      
    //..                                 
 }                                   

 //方法B:循環內定義
 for (int i = 0; i < n; ++i) {
 Widget w(some_value_dependent_on_i);
 //..
 }
  方法A調用了1次構造函數、1次析構函數、n次拷貝函數;
  方法B調用了n次析構函數、n次析構函數。
  
  當 拷貝操作的開銷 比 構造-析構操作 要廉價的時候,一般來說A方法是上選。
  但是A方法中對象的作用域比B方法中更大,也就違背了代碼的集中性和可維護性原則。
  因此,除非
     拷貝操作比構造-析構操作開銷小,并且此部分代碼對性能(performance)要求很高,(此時選擇為A)
  否則B方法還是更合理。


Item 27 : 少做轉型動作
--------------------------------------------------
 tag: cast 轉型    const_cast    dynamic_cast    reinterpret_cast    static_cast
 
 ·盡量避免轉型,特別是注重效率的代碼中避免 dynamic_casts.盡量將要轉型的設計轉化為無需轉型。
 ·若轉型必須,試著將它隱藏于某個函數背后。客戶隨后可以隨時調用該函數,而不需將轉型放進他們自己的代碼中。
 ·另可使用 C++ style轉型,也不要使用舊式轉型。前者更容易分辨。
 
 類型轉換的三種形式(前面兩種都是C風格的舊式類型轉換):
  (T)expression
  T(expression)
  C++ Style:
   const_cast:設置或是去除對象的const屬性。
   dynamic_cast:主要用于繼承關系層次中的向上、向下轉換,以及類之間的交叉轉換。會進行轉換安全性檢查。
   static_cast:可用于內置類型的轉換,以及繼承關系層次中的向上轉換。沒有轉換安全性檢查。
   reinterpret_cast:簡單的強制將一個指針轉換為另外一種指針或整數類型,不做任何檢查。
 
 類型轉換還可能引發額外的代碼運行。比如說dynamic_cast就會通過調用strcmp來比較類的名稱,從而完成繼承關系中不同類對象的轉換,這個時候就不僅僅是簡單的變變類型了。因此,說“類型轉換僅是告訴編譯器把一種類型的數據當成另外一種來參與計算”其實是一個理解上的誤區。
 類型轉換也有可能帶來額外開銷:比如書中用static_cast進行的繼承關系的向上轉換,就會自作主張地生成一個臨時的對象。

 dynamic_cast 通常是在一個認定為 derived class 對象上執行 derived class操作函數,但手上只有一個“指向base”的pointer或reference。
  可以用以下兩種方法來避免這個問題:
  1. 使用容器并在其中存儲直接指向 derived class 對象的指針(通常為智能指針),以消除通過base class接口處理對象的需要。
  2. 在base class內提供virtual函數做你想對各個derived classes做的事。
 要避免所謂的“連串(cascading)dynamic_casts”
 
 在C++中,兩個指向同一個對象的不同指針可能擁有不同的地址值。
 因此,不僅要盡可能的避免轉換類型,而且在不得不使用類型轉換的時候,也應該考慮將轉換的代碼用函數封裝起來。



Item 28 : 避免返回 handles 指向對象內部成分
--------------------------------------------------
 tag: 返回值
 
 避免返回 handles(包括reference、pointer、iterator)指向對象內部。
 增加封裝性,幫助const成員函數的行為像個const,并將發生“懸垂handles”的可能性降至最低。
 

 如果只需要讀訪問,就使用const的返回值,不要開放寫的權限。
 有可能產生懸垂指針(dangling pointer)也是暴露對象內部成員handles的后果之一。
 
 一個返回對象內部成員的函數,在用戶不正確使用的情況下,就有可能產生懸垂指針。
  class AClass{//..};
  class BClass{
  //..
  const AClass& FuncReturningARef();
  //..
  }

  //a possible user's code
  BClass AnObjectOfB;
  const AClass *pAClass = &(AnObjectOfB.FunReturningARef());
  //After the call pAClass becomes a dangeling pointer..
 

Item 29 : 編寫對異常免疫(exception-safe)的代碼
--------------------------------------------------
 tag: Exception safety
 
 ·Exception safety functions即使發生異常也不回泄露字元或允許任何數據結構敗壞。區分為三種可能的保證:基本型、強類型、不拋出異常型
 ·強烈保證型通常能以 copy-and-swap 實現,但強烈保證兵匪對所有函數都可實現或具備現實意義。
 ·函數提供的“Exception-safe保證”通常只等于其所調用之各個函數的“Exception-safe保證"中的最弱者。

 對異常免疫的函數在異常發生的時候應該具備兩個特征:
  不泄漏任何資源(內存、鎖等等)
  不造成任何數據結構的損壞
 并能夠提供至少以下保證中的一項:

 Exception-safe functions 提供以下三個保證之一:
  基本的保證:當異常拋出時,程序中的對象、數據免遭破壞。
  較強的保證:當異常拋出時,程序的狀態不會被改變。若成功調用函數,則系統進入成功后的狀態;如果函數中因異常而出錯,系統應該留在調用函數前的狀態:
  最強的保證:不會有異常拋出。例如對內置類型的操作就不會拋出異常。這是最理想的,但也很難做到。更多的函數只能在前兩者中做一選擇。

 為了能夠提供較強的保證,也即系統的狀態不因異常拋出與否而變化,大師又重新提出了“先拷貝后交換”(copy-and-swap)這一方法論來。
 用不那么嚴謹的說法:為了避免在操作對象時觸發異常影響系統狀態,“先拷貝后交換”先是創建了一個臨時對象,將所有的操作都施加在該臨時對象上。如果沒有出錯,把這個處理過的臨時對象和真正需要處理的對象交換一通,算是順利完成任務;如果有錯并拋出了異常,原系統狀態也不會被影響,因為真正需要處理的對象根本沒有被動過。
 當然,天下沒有免費的午餐。
 “先拷貝后交換”不僅耗費了一個臨時對象的存儲代價,同時支出的還有后面交換對象時的時間和資源開銷。因此,對異常免疫的較強保證是很好很強大,但是實際中并不是任何時候都需要做到那么高的保證。殺雞豈需用牛刀?

 最后要提醒的是,對異常免疫的函數也符合“短板理論”:木桶能裝的水與其最短的那塊木板有關,函數對異常免疫的程度也由函數中程度最低的代碼(包括其調用的函數)決定。某個函數如果調用了另外一個一出現異常就崩潰的函數,那么這個函數就不能提供基本的異常免疫保證。


Item 30 : 透徹了解 inlining
--------------------------------------------------
 tag: inline
 ·將大多數 inlining 限制在小型、被頻繁調用的函數身上。可使日后的調用過程和二進制升級更容易,也使程序的速度提升機會更大。
 ·不要只因為 function templates 出現在頭文件,就將他們聲明為 inline.
 
 使用內聯函數(inline function)可以省去一般函數調用的入棧操作開銷,比宏(macro)要好用。從編譯器的角度來看,沒有函數調用的代碼要更容易優化。
 但是天下沒有免費的午餐,以空間換時間的內聯函數同時也帶來了更大的程序占用空間,更甚者還會因為這變大的代碼空間導致額外的內存換頁操作,降低指令緩存(instruction cache)的命中率……這些都是使用內聯函數需要考慮到的負面影響。(Scott還是辯證地提醒了一點:當內聯函數非常短小時,相比一般意義上的函數調用,它能夠幫助編譯器生成更小的最終代碼和運行時更高的指令緩存命中率)

 內聯函數的聲明可以是顯式的:使用inline關鍵字;也可以是隱式的:在類的定義中定義函數。

 內聯函數一般而言都是定義在頭文件中,這是因為大多數編譯器的內聯動作都是發生在編譯過程中。(也有著鏈接甚至是運行中才進行內聯的,但是俺們這里隨大流,講主要矛盾)
 雖然內聯函數和函數模板有一點相似:它們都幾乎定義在頭文件中,但是這兩者之間沒有必然聯系,而非有的程序員想的那樣“函數模板一定是內聯的”)

 內聯函數的定義僅僅是對編譯器提出內聯的請求。編譯器完全有可能忽視這個請求,于是某“內聯函數”有可能在最后還是生成了一般函數的代碼:

  請求內聯的函數有可能太過于復雜
  請求內聯的函數有可能是虛函數(虛函數的真正實體要在運行時才能得知,讓編譯器編譯階段去做內聯實在有點強人所難)
  請求內聯的函數沒什么問題,但是在代碼中有用函數指針的方式調用該函數(這樣編譯器也沒辦法,如果不生成一般函數哪來的函數指針?)
  這些情況下確實不應該把函數作為內聯函數。一個“內聯函數”是否最終生成了內聯函數,還得編譯器說了算。
 然而編譯器并不是總能幫助我們做出正確的決定,還有一些情況是需要我們自己做出判斷的:

 請求內聯的函數是構造/析構函數(表面上看起來某個構造/析構函數很短小甚至是空的,但是為了構造/析構類中的其他成員,編譯器有可能會“自覺”地寫入必要的代碼,這樣的構造/析構函數就有可能不適合再做內聯了)這一點原文中有更詳細的說明。
 當編寫支持庫時(library)也不建議使用內聯函數,因為一旦用戶使用了這些含有內聯函數的庫并編譯了自己的程序,這些內聯函數就已經“寫死”在他們的程序中了。當日后對原先的庫做了更新修改,用戶就必須重新編譯整個程序才能用上新的補丁。而一般的函數就不會有這個問題:他們是動態鏈接的,用戶根本感覺不到任何改動。
 考慮到很多調試器(debugger)無法調試內聯函數(本來就沒有這么一個“函數”,叫人家怎么設斷點?),在調試版本中也不建議使用內聯函數。
 有那么多需要注意的地方,大師最后總結了一下:用好內聯函數的第一步就是:不用內聯函數。并沒有那么多的函數真正需要內聯,因為80%的程序運行時間都是花在了20%的代碼中。第二步是把內聯函數當成是手工優化的手段,僅僅在非常需要效率和優化的代碼中使用內聯。



Item 31 : 將文件間的編譯依存關系降至最低
--------------------------------------------------
 tag: Handle class,Interface classes ,  接口類 實現類,
 ·相依于聲明式,不要相依于定義式。兩個手段來實現:Handle classes 和 Interface classes.
 ·程序庫頭文件應該以 “ 完全且僅有聲明式 ”(full and declaration-only forms)的形式存在,不論是否涉及 templates.
 
 大師說了,C++的設計還是有缺陷的:它無法把接口(interface)的設計和實現(implementation)的設計完全劃分開來。
 比如說在一個類的(接口)聲明當中,總是或多或少的會泄漏一些實現上的細節,雖然這樣做與接口的設計并沒有太多聯系。

  class  AClass  {
  public :
     void  interface_1();
     std::string  interface_2();
  private :
     //  implementation details are leaking as below..
     std::string  internalData_1;
     BClass internalData_2;
  }   

 往往還需要引用其他頭文件中相關對象的定義(如下面的代碼),從而產生了對這些頭文件的(在編譯時的)依賴。因此每次這些文件中的某個有變化時,依賴它的所有文件都需要重新編譯。
  #include  < string >
 #include  " BClass.h "  //
 
 【注意】這里貌似邏輯不是很順:就算沒有那些私有成員的聲明,接口函數的返回值如果是string或是BClass等類型,不還是一樣需要依賴引用其他頭文件嗎?
 這是兩種不一樣的情況,實現和接口。
  前面說的實現細節的泄漏是會導致編譯依賴的,因為編譯器需要了解這些類型對象的大小進而為其分配內存空間;
  但是接口,比如說函數的返回值或是參數表中的參數,就不需要編譯器去考慮分配內存的問題,因此也就沒有所謂的編譯依賴了。


 將類分割為兩個classes,一個只提供接口,另一個負責實現該接口。
   class  AClassImpl 
   {
   private :
      //  implementation details are moved here..
      std::string  internalData_1;
      BClass internalData_2;
   }
  
   class  AClass 
   {
   public :
      void  interface_1();
      std::string  interface_2();
   private :
      //  there is only a pointer to implementation
      std::tr1::shared_ptr < AClassImpl >  pImpl;
  }
  
   // a constructor: instantiations of AClass and AClassImpl should always be bound together.
   AClass::AClass( // ..) : pImpl(new AClassImpl( // ..))
   {   } 

 分離的關鍵在于以“聲明的依存性”替換“定義的依存性”:讓頭文件盡可能自我滿足,如果不行,就讓它與其他文件內的聲明式(而非定義式)相依:
 ·若使用 object references 或 object pointers 可以完成任務,就不要使用 objects.但如果要定義某類型的object,就需要用到定義式,。
 ·盡量以class聲明式替換class定義式。
 ·為聲明式和定義式提供不同的頭文件。

 第二種方法中,抽象類/接口類提供了所有接口的純虛函數形式:會有該類的子類去實現這些接口。
 在抽象類/接口類中還會有一個靜態(static)的工廠函數(比如create()/produce()/factory()……),這個函數實際上起到了構造函數的作用,它“制造”出子類對象來完成真正的任務,同時返回這個對象的指針(通常是智能指針如shared_ptr)。憑借這個返回的指針就可以進行正常的操作,同時不會有編譯依賴的擔心。一個簡陋的代碼見下:

  class  AClass: public  AClassFactory  {
  public :
      AClass()   {}
      void  interface_1();
      std:: string  interface_2();
      virtual   ~ AClass();
  }
 
  class  AClassFactory  {
  public :
      virtual   void  interface_1()  =   0 ;
      virtual  std::string  interface_2()  =   0 ;
      virtual   ~AClassFactory()  { /* .. */ }
      static  std::tr1::shared_ptr < AClassFactory >  Produce( /* .. */ )
      {
         // this factory function could be more complicated in practice..
         return  std::tr1::shared_ptr < AClassFactory > ( new  AClass);
      }
  }
 
 
  // AClassFactory could be used in this way..
  std::tr1::shared_ptr < AClassFactory >  pAClassObject;
  pAClassObject  =  AClassFactory::Produce( /* .. */ );
  // pAClassObject->..

 


 

posted on 2010-03-15 22:53 Euan 閱讀(506) 評論(0)  編輯 收藏 引用 所屬分類: C/C++
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            久久九九全国免费精品观看| 午夜影视日本亚洲欧洲精品| 欧美v国产在线一区二区三区| 欧美淫片网站| 激情亚洲网站| 亚洲电影免费| 欧美精品三级日韩久久| 99国产精品国产精品久久| 99国内精品久久| 国产裸体写真av一区二区| 久久久999精品| 能在线观看的日韩av| 在线一区亚洲| 久久久97精品| 亚洲图色在线| 久久国产日韩| 亚洲一区二区免费在线| 久久成人18免费观看| 亚洲精品欧美激情| 亚洲在线视频网站| 亚洲欧洲视频| 午夜精品久久久久久久久久久| 在线观看亚洲| 亚洲一区二区少妇| 亚洲精品日日夜夜| 欧美亚洲一区二区在线| 99re亚洲国产精品| 久久久777| 午夜激情综合网| 欧美乱人伦中文字幕在线| 久久精品国产亚洲一区二区三区 | 久久人人97超碰精品888| 久久综合久久88| 欧美一级片在线播放| 欧美大片在线观看| 欧美另类videos死尸| 欧美日韩精品一区二区| 久久久噜噜噜久噜久久| 欧美三级在线| 欧美黑人多人双交| 国产日韩在线播放| 亚洲午夜伦理| 一区二区三区四区五区视频| 模特精品在线| 牛牛影视久久网| 国产揄拍国内精品对白| 亚洲一级免费视频| 亚洲自拍偷拍福利| 欧美日韩国产美| 亚洲国产一区在线观看| 在线精品福利| 久久亚洲二区| 欧美成人久久| 亚洲日本中文| 欧美激情亚洲综合一区| 欧美激情精品久久久久久| 激情综合色丁香一区二区| 午夜精品一区二区三区在线播放 | 国产一区二区三区久久悠悠色av| 一区二区不卡在线视频 午夜欧美不卡'| 亚洲三级视频在线观看| 你懂的国产精品| 亚洲国产视频一区二区| 亚洲国产日韩在线一区模特| 久久综合狠狠| 亚洲国产天堂久久综合网| 日韩香蕉视频| 欧美日韩在线看| 一本大道久久a久久综合婷婷 | 久久久久国产一区二区| 国产主播喷水一区二区| 久久精品国产第一区二区三区最新章节 | 国产一区免费视频| 久久国产欧美日韩精品| 欧美www视频在线观看| 亚洲欧洲视频| 国产精品成人免费精品自在线观看| 一区二区欧美精品| 久久成人免费网| 加勒比av一区二区| 欧美国产亚洲精品久久久8v| 99国产精品久久久久久久成人热| 欧美在线免费视频| 亚洲国产精品成人| 欧美日韩国产综合视频在线观看 | 欧美怡红院视频一区二区三区| 久久夜色精品国产欧美乱| 亚洲区在线播放| 国产精品日韩二区| 久久综合色婷婷| 亚洲社区在线观看| 你懂的视频欧美| 亚洲欧美国产一区二区三区| 国产综合av| 欧美日韩理论| 久久男女视频| 尤物视频一区二区| 亚洲欧美资源在线| 欧美国产一区二区在线观看| 亚洲欧美激情四射在线日 | 国产区亚洲区欧美区| 久久色在线观看| 亚洲一级一区| 亚洲国产成人在线视频| 欧美一区二区三区在线播放| 亚洲激情社区| 国产亚洲va综合人人澡精品| 欧美精品一区二区三区蜜臀| 欧美在线观看一区二区| 一本一本久久| 亚洲福利av| 麻豆精品精华液| 欧美一区在线看| 在线视频欧美精品| 亚洲激情在线播放| 国内外成人在线| 国产精品视频精品| 欧美日韩一级片在线观看| 久久久久综合| 欧美自拍偷拍午夜视频| 亚洲一区二区在线免费观看视频 | 欧美成人在线影院| 久久精品一二三| 欧美有码在线观看视频| 亚洲性人人天天夜夜摸| 一本色道久久综合亚洲精品婷婷| 亚洲国产精品电影| 欧美国产乱视频| 美女精品在线观看| 久久久无码精品亚洲日韩按摩| 亚洲欧美日韩国产一区二区| 一区二区三区四区精品| 99一区二区| 一本大道久久a久久精品综合| 亚洲激情视频网| 日韩亚洲成人av在线| 亚洲日本理论电影| 亚洲伦理精品| 日韩一级成人av| 一区二区三区 在线观看视频 | 亚洲精品乱码视频| 最新国产乱人伦偷精品免费网站 | 欧美日韩在线视频观看| 欧美日韩视频在线第一区| 欧美另类videos死尸| 欧美日韩精品欧美日韩精品| 欧美日韩福利在线观看| 欧美日韩另类视频| 国产精品免费看| 国产一区二区三区成人欧美日韩在线观看 | 国产精品亚洲美女av网站| 国产日韩精品一区二区| 国产视频久久久久久久| 狠狠狠色丁香婷婷综合激情| 黑人极品videos精品欧美裸| 好吊视频一区二区三区四区| 一区二区三区四区五区精品视频 | 亚洲精选国产| 亚洲天堂成人| 性久久久久久| 麻豆精品网站| 91久久久久久| 亚洲校园激情| 久久综合九色| 国产精品国产三级欧美二区 | 欧美天天在线| 国外成人在线| 日韩五码在线| 久久激情视频| 亚洲黄色在线视频| 亚洲一区免费看| 巨胸喷奶水www久久久免费动漫| 欧美成人中文| 国产亚洲va综合人人澡精品| 亚洲日本精品国产第一区| 亚洲专区在线| 欧美r片在线| 亚洲欧美日韩一区二区三区在线 | 亚洲视频精品在线| 久久不射中文字幕| 欧美日韩综合一区| 亚洲第一精品夜夜躁人人爽 | 欧美一区高清| 亚洲国产日韩欧美在线99| 亚洲欧美美女| 欧美日韩理论| 91久久精品国产91性色| 久久九九全国免费精品观看| 亚洲乱码国产乱码精品精98午夜 | 欧美电影免费观看高清完整版| 国产乱码精品一区二区三区忘忧草| 亚洲第一中文字幕| 久久久精品一区| 亚洲在线观看免费视频| 欧美激情一区二区三区全黄| 黄色精品网站| 久久久久网址| 性视频1819p久久| 国产精品久久久久秋霞鲁丝| 99精品欧美一区二区蜜桃免费|