• <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>

            Shuffy

            不斷的學習,不斷的思考,才能不斷的進步.Let's do better together!
            posts - 102, comments - 43, trackbacks - 0, articles - 19
            【轉】http://m.shnenglu.com/tiandejian/archive/2007/08/19/EC_26.html

            第五章.        實現

            在大多數情況下,恰當地做好類(以及類模板)的定義和函數(以及函數模板)的聲明是整個實現工作的重中之重。一旦你順利地完成了這些工作,那么相關的實現工作大都是直截了當的。然而,這里還存在一些需要關注的事情:過早地定義變量可能會犧牲性能。濫用轉型可能會使代碼變得笨重且不以維護,同時也會困擾于無盡難于發現的 bug 。返回一個對象內部內容的句柄會破壞代碼的封裝性,同時留給客戶端程序員一個懸而未決的“野句柄”。如果對異常的影響考慮不周,那么將會帶來資源泄露和數據結構的破壞。過分熱衷于使用內聯會使代碼不斷膨脹。代碼文件過多過復雜會造成的過于復雜的耦合,程序的構建時間會漫長得讓人無法忍受。

            所有這些問題都是可以避免的。本章就來講解如何去做。


             

             

            第26條:     定義變量的時機越晚越好

            你經常要使用構造函數或者析構函數來定義某個類型的一個變量,當系統控制在接收到這一變量的定義時,就引入了一次構造過程的開銷;在變量達到自身作用域以外時,就引入一次析構過程的開銷。未使用的變量也會帶來一定的開銷,所以你應該盡可能的避免這種浪費的出現。

            你可能會想你永遠也不會定義變量而不去使用,但是你可能需要三思而后行。請觀察下邊的函數,它在所提供的密碼足夠長時,可以返回一個加密版本的密碼。如果密碼長度過短,函數就會拋出一 logic_error 型的異常(這個異常類型定義于標準 C++ 庫中,參見第 54 條):

            // 這個函數定義 "encrypted" 變量的時機過早

            std::string encryptPassword(const std::string& password)

            {

             using namespace std;

             

             string encrypted;

             

             if (password.length() < MinimumPasswordLength) {

                 throw logic_error("Password is too short");

             }

             ...                            // 對密碼加密

             return encrypted;

            }

            本函數中,對象 encrypted 并不是完全未使用的,但是在拋出異常的情況下,函數就不會使用它。也就是說,即使 encryptPassword 拋出一個異常的話,你也要為 encrypted 付出一次構造和一次析構的代價。因此,你最好這樣做:推遲 encrypted 的定義,直到你確認你需要它時再進行

            // 這個函數推遲了 encrypted 的定義,直到真正需要它時再進行

            std::string encryptPassword(const std::string& password)

            {

             using namespace std;

             

             if (password.length() < MinimumPasswordLength) {

                 throw logic_error("Password is too short");

             }

             

             string encrypted;

             

             ...                            // 對密碼加密

             return encrypted;

            }

            上面的代碼還不像你想象的那么嚴謹,這是因為在定義 encrypted 是沒有為它設置任何初始化參數。這就意味著編譯器將調用它的默認構造函數。通常情況下,你要對一個對象需要做的第一件事就是為它賦一個值,通常是通過一次賦值操作。第 4 條中解釋了為什么使用默認構造函數構造對象并為其賦值,要比使用需要的值對其進行初始化的效率低一些。那里的分析符合此處的情況。比如說,可以假設的較困難的部分是通過下面的函數來解決的:

            void encrypt(std::string& s);             // encrypts s in place

            encryptPassword 就應該以下面的方式來實現了,盡管它不是最優秀的:

            // 這一函數推遲了 enctypted 定義的時機,直到需要時才進行。

            // 但仍然會帶來不必要的效率問題。

             

            std::string encryptPassword(const std::string& password)

            {

             ...                            // 同上,檢查密碼長度

             

             std::string encrypted;         // encrypted 的默認構造函數版本

             encrypted = password;           // encrypted 賦值

             

             encrypt(encrypted);

             return encrypted;

            }

            更好的一種實現方式是,使用 password 來初始化 encrypted ,這樣就可以跳過默認構造過程所帶來的無謂的性能開銷:

            // 最后給出定義和初始化 encrypted 的最佳方法

             

            std::string encryptPassword(const std::string& password)

            {

             ...                              // 檢查長度

             

             std::string encrypted(password);// 通過拷貝構造函數定義和初始化

             

             encrypt(encrypted);

             return encrypted;

            }

            此時標題中 的“越 越好”的含義就十分明顯了。你不僅僅要推遲一個變量的定義時機,直到需要它時再進行;你還需要繼續推遲,直至你掌握了它的初始化參數為止。這樣做,你就可以避免去構造和析構不必要的對象,你也可以避免那些無關緊要的默認構造過程。還有,通過初始化這些變量,定義這些變量的目的一目了然,從而代碼也變得更加清晰。

            “但是循環呢?”你可 能會想。如果一個變量僅僅在循環題中使用,那么更好的選擇是:將它定義在循環題的外部,在每次循環迭代前對其進行賦值;還是:在循環體的內部定義變量?也就是說,哪種基本結構是更優秀的呢?

            // 方法 A :在循環體外部定義

             

            Widget w;

             

            for (int i = 0; i < n; ++i){

             w = 取決于 i 的某個值 ;

             ...

            }

             

            // 方法 B: 在循環體內部定義

             

            for (int i = 0; i < n; ++i) {

            Widget w( 取決于 i 的某個值 ) ;

             ...

            }

            這里我使用了 Widget 類型的對象,而不是 string 類型的對象,從而避免了進行構造、析構、或者對象賦值等過程帶來的誤差。

            對于 Widget 的操作而言,上面兩種方法所帶來的開銷如下:

            方法 A 1 個構造函數 + 1 個析構函數 + n 次賦值。

            方法 B n 個構造函數 + n 個析構函數。

            對于那些一次賦值操作比一對構造 - 析構操作開銷更低的類而言,方法 A 是較高效的。尤其是在 n 較大的情況下。否則方法 B 就是更好的選擇。還有,方法 A 使得 w 位于一個比方法 B 更大的作用域中,這是違背程序的可讀性和可維護性原則的。因此,除非你確認 : (1) 賦值操作比一對構造 - 析構操作更高效, (2) 當前代碼是對性能敏感的;其他任何情況下,你都應該使用方法 B

            銘記在心

            定義變量的時機越晚越好。這可以提高程序的清晰度和工作效率。

            久久亚洲精品视频| 一级做a爰片久久毛片看看| 久久精品中文闷骚内射| 国产欧美久久久精品| 国产精品久久久天天影视香蕉 | 久久夜色精品国产亚洲av| 久久精品卫校国产小美女| 久久精品国产亚洲AV香蕉| 一本一道久久精品综合| 日本精品久久久久久久久免费| 亚洲中文字幕无码一久久区 | 久久亚洲av无码精品浪潮| 浪潮AV色综合久久天堂| 久久久久国产精品三级网| 精品久久久无码人妻中文字幕豆芽 | 久久免费99精品国产自在现线| 久久久久久综合网天天| 精品无码人妻久久久久久| 亚洲综合伊人久久综合| 亚洲精品乱码久久久久久蜜桃 | 亚洲欧洲精品成人久久曰影片| 国内精品伊人久久久久AV影院| 久久婷婷人人澡人人爽人人爱| 99久久婷婷国产综合精品草原| 人妻无码αv中文字幕久久| 怡红院日本一道日本久久| 久久无码人妻一区二区三区 | 久久精品国产91久久麻豆自制| 亚洲精品美女久久久久99| 理论片午午伦夜理片久久| 国产综合精品久久亚洲| 93精91精品国产综合久久香蕉| 激情伊人五月天久久综合| 99久久er这里只有精品18| 看久久久久久a级毛片| 国产人久久人人人人爽| 国内精品久久久久久99蜜桃| 国产精品美女久久久久网| 久久九九全国免费| 国产精品日韩深夜福利久久| 久久亚洲国产午夜精品理论片|