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