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

            洛譯小筑

            別來無恙,我的老友…
            隨筆 - 45, 文章 - 0, 評論 - 172, 引用 - 0
            數(shù)據(jù)加載中……

            [ECPP讀書筆記 條目26] 定義變量的時機(jī)越晚越好

            你經(jīng)常要使用構(gòu)造函數(shù)或者析構(gòu)函數(shù)來定義某個類型的一個變量,當(dāng)系統(tǒng)在運(yùn)行至變量的定義時,就會引入一次構(gòu)造的開銷;在變量達(dá)到自身作用域的邊界時,就會引入一次析構(gòu)的開銷。未使用的變量也會帶來一定的開銷,所以你應(yīng)該盡可能的避免這種浪費(fèi)的出現(xiàn)。

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

            // 這個函數(shù)定義"encrypted"變量的時機(jī)過早

            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;

            }

            本函數(shù)中,盡管對象encrypted并不是完全未使用的,但是在拋出異常的情況下,函數(shù)就不會使用它。也就是說,即使encryptPassword拋出一個異常,你也要為encrypted付出一次構(gòu)造和一次析構(gòu)的代價。因此,你最好推遲encrypted的定義,直到你確認(rèn)你需要它時再進(jìn)行:

            // 這個函數(shù)推遲了encrypted的定義,直到真正需要它時再進(jìn)行

            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;

            }

            上面的代碼還沒有那么嚴(yán)謹(jǐn),這是因?yàn)樵诙xencrypted時沒有為它設(shè)置任何初始化參數(shù)。這就意味著編譯器將調(diào)用它的默認(rèn)構(gòu)造函數(shù)。通常情況下,你要對一個對象需要做的第一件事就是為它賦一個值,通常是通過一次賦值操作。條目4中解釋了為什么使用默認(rèn)構(gòu)造函數(shù)構(gòu)造對象并為其賦值,要比使用需要的值對其進(jìn)行初始化的效率低一些。那里的分析符合此處的情況。比如說,可以假設(shè)的較困難的部分是通過下面的函數(shù)來解決的:

            void encrypt(std::string& s);     // 適時為s加密

            encryptPassword就應(yīng)該以下面的方式來實(shí)現(xiàn)了,盡管它不是最優(yōu)秀的:

            // 這一函數(shù)推遲了enctypted定義的時機(jī),直到需要時才進(jìn)行。

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

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

            {

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

             

              std::string encrypted;           // encrypted的默認(rèn)構(gòu)造函數(shù)版本

              encrypted = password;            // encrypted賦值

             

              encrypt(encrypted);

              return encrypted;

            }

            更好的一種實(shí)現(xiàn)方式是,使用password來初始化encrypted,這樣就可以跳過默認(rèn)構(gòu)造過程所帶來的無謂的性能開銷:

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

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

            {

              ...                              // 檢查長度

             

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

             

              encrypt(encrypted);

              return encrypted;

            }

            此時標(biāo)題中的越晚越好的真正含義就十分明顯了。你不僅僅要推遲一個變量的定義時機(jī),直到需要它時再進(jìn)行;你還需要繼續(xù)推遲,直至你掌握了它的初始化參數(shù)為止。這樣做,你就可以避免去構(gòu)造和析構(gòu)不必要的對象,你也可以避免那些無關(guān)緊要的默認(rèn)構(gòu)造過程。還有,通過初始化這些變量,定義這些變量的目的一目了然,從而代碼也變得更加清晰。

            但是循環(huán)呢?你可能會想。如果一個變量僅僅在循環(huán)題中使用,那么更好的選擇是:將它定義在循環(huán)題的外部,在每次循環(huán)迭代前對其進(jìn)行賦值;還是:在循環(huán)體的內(nèi)部定義變量?也就是說,哪種基本結(jié)構(gòu)是更優(yōu)秀的呢?

            // 方法A:在循環(huán)體外部定義

             

            Widget w;

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

              w = 取決于i的某個值;

              ...

            }

             

            // 方法B: 在循環(huán)體內(nèi)部定義

             

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

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

              ...

            }

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

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

            方法A:1個構(gòu)造函數(shù) + 1個析構(gòu)函數(shù) + n次賦值。

            方法B:n個構(gòu)造函數(shù) + n個析構(gòu)函數(shù)。

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

            時刻牢記

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

             

            posted on 2007-08-19 22:00 ★ROY★ 閱讀(1165) 評論(0)  編輯 收藏 引用 所屬分類: Effective C++

            中文字幕无码久久久| 色播久久人人爽人人爽人人片aV| 国产AⅤ精品一区二区三区久久| 2019久久久高清456| 欧美精品一区二区久久| 久久精品亚洲乱码伦伦中文| 99久久综合狠狠综合久久| 一级做a爰片久久毛片人呢| 青青青伊人色综合久久| 精品一区二区久久久久久久网站| 成人国内精品久久久久一区| 久久久久久夜精品精品免费啦| 久久精品国产网红主播| 久久久久久a亚洲欧洲aⅴ| 99久久www免费人成精品| 久久福利片| 一本综合久久国产二区| 精品久久亚洲中文无码| 欧美午夜精品久久久久免费视 | 亚洲精品乱码久久久久久中文字幕| 欧美精品福利视频一区二区三区久久久精品 | 国产巨作麻豆欧美亚洲综合久久 | 18禁黄久久久AAA片| 欧美黑人又粗又大久久久| 国产韩国精品一区二区三区久久| 99久久99这里只有免费的精品| 久久99热狠狠色精品一区| 人妻系列无码专区久久五月天| 亚洲精品国精品久久99热一| 久久99国产综合精品免费| 久久精品一区二区影院| 伊人久久综合精品无码AV专区| 99久久人妻无码精品系列| 久久久无码精品亚洲日韩软件| 无码人妻久久久一区二区三区| 久久亚洲国产欧洲精品一| 亚洲精品第一综合99久久 | 99精品国产99久久久久久97| 久久精品a亚洲国产v高清不卡| 精品无码人妻久久久久久| 日韩人妻无码精品久久久不卡 |