《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 中更小,更有利于程序的可理解性和易维护性。
** 请记住: **
尽可能延后变量定义式的出现。这样做可增加程序的清晰度并改善程序效率。