《Effective C++ 中文版 第三版》讀書筆記
** 條款 26:盡可能延后變量定義式的出現實現時間 **
只要定義一個變量,而其類型帶有一個構造函數或析構函數,
那么當程序的控制流到達這個變量定義時,變承受構造成本;當變量離開作用域時,便承受析構成本。
// 這個函數過早定義變量 “encrypted”
std::string encryptPassword(const std::string& password)
{
using namespace std;
string encrypted;
if(password.length() < MinimumPasswordLengt)
{
throw logic_error(“Password is too short”)
}
…// 必要動作,將一個加密后的密碼置入 encrypted 內。
return encypted;
}
如果函數 encryptPassword 丟出異常,你仍得付出 encrypted 的構造和析構成本。所以最好延后 encrypted 的定義式。直到確定需要它:
// 這個函數延后 “encrypted” 的定義,直到真正需要它
std::string encryptPassword(const std::string& password)
{
using namespace std;
if(password.length() < MinimumPasswordLengt)
{
throw logic_error(“Password is too short”)
}
string encrypted;
…//< 必要動作,將一個加密后的密碼置入 encrypted 內。
return encypted;
}
Encrypted 雖獲定義卻無任何參數作為初值。這意味調用的是 default 構造函數。許多時候你對該對象做的第一個動作就是給它個值,通常通過賦值動作完成。
```cpp
void encrypt(std::string& s);
std::string encryptPassword(const std::string& password)
{
using namespace std;
if(password.length() < MinimumPasswordLengt)
{
throw logic_error(“Password is too short”)
}
std::string encrypted; //< default-construct encrypted
encrypted = password; //< 賦值給 encrypted
encrypt(encrypted);
return encypted;
}
更受歡迎的做法是以 password 作為 encrypted 的初值,跳過毫無意義的 default 構造函數過程:
std::string encryptPassword(const std::string& password)
{
using namespace std;
if(password.length() < MinimumPasswordLengt)
{
throw logic_error(“Password is too short”)
}
std::string encrypted(password); //< 通過 copy 構造函數定義并初始化。
encrypt(encrypted);
return encypted;
}
“盡可能延后”的意義。不只應該延后變量的定義,直到非得使用該變量的前一刻為止,甚至應該嘗試延后這份定義直到能夠給他初值參數為止。不僅能避免構造(和析構)非必要對象,還可以避免無意義的 default 構造行為。
對于循環:
//方法A:定義于循環外
Widget w;
for(int i = 0; i < n; i++)
{
w = 取決于某個i的值;
//…
}
//方法B:定義于循環內
for(int i = 0; i < n; i++)
{
Widget w(取決于i的某個值);
//…
}
做法A:1 個構造 + 1 個析構 + n 個賦值
做法B:n 個構造 + n 個析構
如果 1.賦值成本比 “構造 + 析構” 成本低,2.正在處理效率高度敏感的部分,否則應該使用 B;B 中 w 作用域比 A 中更小,更有利于程序的可理解性和易維護性。
** 請記住: **
盡可能延后變量定義式的出現。這樣做可增加程序的清晰度并改善程序效率。