C++箴言:只要有可能就推遲變量定義

字號(hào):

在極大程度上,為你的類(包括類模板)和函數(shù)(包括函數(shù)模板)提供正確的定義是戰(zhàn)斗的關(guān)鍵性部分。一旦你得到正確的結(jié)果,相應(yīng)的實(shí)現(xiàn)很大程度上就是直截了當(dāng)?shù)?。但是仍然有一些注意事?xiàng)需要當(dāng)心。過早地定義變量會(huì)對(duì)性能產(chǎn)生拖累。過度使用強(qiáng)制轉(zhuǎn)換會(huì)導(dǎo)致緩慢的,難以維護(hù)的,被微妙的 bug 困擾的代碼。返回一個(gè)類內(nèi)部構(gòu)件的句柄會(huì)破壞封裝并將空懸句柄留給客戶。疏忽了對(duì)異常產(chǎn)生的影響的考慮會(huì)導(dǎo)致資源的泄漏和數(shù)據(jù)結(jié)構(gòu)的破壞。過分內(nèi)聯(lián)化(inlining)會(huì)導(dǎo)致代碼膨脹。過度的耦合會(huì)導(dǎo)致令人無法接受的漫長(zhǎng)的建構(gòu)時(shí)間。 這一切問題都可以避免。
    只要有可能就推遲變量定義
    只要你定義了一個(gè)帶有構(gòu)造函數(shù)和析構(gòu)函數(shù)的類型的變量,當(dāng)控制流程到達(dá)變量定義的時(shí)候會(huì)使你擔(dān)負(fù)構(gòu)造成本,而當(dāng)變量離開作用域的時(shí)候會(huì)使你擔(dān)負(fù)析構(gòu)成本。如果有無用變量造成這一成本,你就要盡你所能去避免它。
    你可能認(rèn)為你從來不會(huì)定義無用的變量,但是也許你應(yīng)該再想一想??紤]下面這個(gè)函數(shù),只要 password 的長(zhǎng)度滿足要求,它就返回一個(gè) password 的加密版本。如果 password 太短,函數(shù)就會(huì)拋出一個(gè)定義在標(biāo)準(zhǔn) C++ 庫(kù)中的 logic_error 類型的異常(參見 Item 54):
    // this function defines the variable "encrypted" too soon
    std::string encryptPassword(const std::string& password)
    {
    using namespace std;
    string encrypted;
    if (password.length() < MinimumPasswordLength) {
    throw logic_error("Password is too short");
    }
    ... // do whatever is necessary to place an
    // encrypted version of password in encrypted
    return encrypted;
    }
    對(duì)象 encrypted 在這個(gè)函數(shù)中并不是完全無用,但是如果拋出了一個(gè)異常,它就是無用的。換句話說,即使 encryptPassword 拋出一個(gè)異常,你也要為構(gòu)造和析構(gòu) encrypted 付出代價(jià)。因此得出以下結(jié)論:你將 encrypted 的定義推遲到你確信你真的需要它的時(shí)候:
    // this function postpones encrypted’s definition until it’s truly necessary
    std::string encryptPassword(const std::string& password)
    {
    using namespace std;
    if (password.length() < MinimumPasswordLength) {
    throw logic_error("Password is too short");
    }
    string encrypted;
    ... // do whatever is necessary to place an
    // encrypted version of password in encrypted
    return encrypted;
    }
    這一代碼仍然沒有達(dá)到它本可以達(dá)到的那樣緊湊,因?yàn)槎x encrypted 的時(shí)候沒有任何初始化參數(shù)。這就意味著很多情況下將使用它的缺省構(gòu)造函數(shù),對(duì)于一個(gè)對(duì)象你首先應(yīng)該做的就是給它一些值,這經(jīng)常可以通過賦值來完成我已經(jīng)解釋了為什么缺省構(gòu)造(default-constructing)一個(gè)對(duì)象然后賦值給它比用你真正需要它持有的值初始化它更低效。那個(gè)分析也適用于此。例如,假設(shè) encryptPassword 的核心部分是在這個(gè)函數(shù)中完成的:
    void encrypt(std::string& s); // encrypts s in place