声明:
- 文中内容收集整理自《Effective C++(中文版)第三版》,版权归原书所有。
- 本内容在作者现有能力的基础上有所删减,另加入部分作者自己的理解,有纰漏之处敬请指正。
条款26:尽可能延后变量定义式出现的时间
Pospone variable definations as long as possible.
只要定义一个变量而其类型带有一个构造函数或析构函数,那么当程序的控制流到达这个变量定义式时,便得承受构造成本;当变量离开作用域时,便得承受析构成本。
void encrypt(std::string& s); //在适当的地点对s进行加密
std::string encryptPassword(const std::string& password)
{
using namespace std;
//string encrypted; //过早定义变量 “encrypted”
if(password.length() < MinimumPasswordLength)
{
throw logic_error("Password is too short");
}
//不如把变量定义到这里
//通过“copy构造函数定义并初始化”要比“通过default构造函数构造出一个对象然后对其进行赋值”效率要高
string encrypted(password);
encrypt(encrypted);// 必要动作,如将一个加密后的密码置入encrypted内。
return encypted;
}
如果函数 encryptPassword 丢出异常,你仍得付出 encrypted 的构造和析构成本。所以最好延后 encrypted 的定义式,直到确实需要它。
“尽可能延后”的真正意义
不只应该延后变量的定义,直到非得使用该变量的前一刻为止,甚至应该尝试延后这份定义直到能够给他初值实参为止(如上例子所述)。这样不仅能避免构造(和析构)非必要对象,还可以避免无意义的 default 构造行为。
“但循环怎么办?”
如果变量只在循环内使用,那么把它定义于循环外并在每次循环迭代赋值给它比较好,还是该把它定义于循环内?(之前做开发的时候遇到过这个问题,当时好像是使用的方法B,非常耗时;改为方法A,瞬间效率提升了很多很多很多……)
//方法A:定义于循环外
Widget w;
for(int i = 0; i < n; i++)
{
w = 取决于某个i的值;
...
}
//方法B:定义于循环内
for(int i = 0; i < n; i++)
{
Widget w(取决于i的某个值);
...
}
在Widget函数内部,以上两种写法的成本如下:
- 做法A:1 个构造 + 1 个析构 + n 个赋值
- 做法B:n 个构造 + n 个析构
如果:(1)你知道赋值成本比 “构造 + 析构” 成本低;(2)正在处理的代码对效率高度敏感,可以考虑使用A,否则应该使用 B。注意到B 中 w 作用域比 A 中更小,更有利于程序的可理解性和易维护性。
请记住:
尽可能延后变量定义式的出现。这样做可增加程序的清晰度并改善程序效率。