C++实现之——延后变量定义
如果你定义了一个变量而其类型带有一个构造函数和析构函数,那么当程序的程序流到达这个变量定义式时,你便得承受构造成本;当这个变量离开其作用域时,你便得承受析构成本,即使这个变量最终并未被使用,你仍需耗费这些成本,如下面的代码:
1 string encryptPwd(const string& pwd) 2 { 3 string encrypted; 4 if(pwd.length() < MinimumLength) 5 { 6 throw logic_error("Pwd is too short!"); 7 } 8 ... 9 return encrypted; 10 }
上面的代码中,如果if语句中抛出异常,那么encrypted变量就未被使用,但它依然调用了string类的构造函数和析构函数,为了避免这种开销,可以将变量延后,代码修改如下:
1 string encryptPwd(const string& pwd) 2 { 3 if(pwd.length() < MinimumLen) 4 { 5 thorw logic_error("Pwd is too short!"); 6 } 7 string encrypted; 8 encrypted = pwd; 9 encrypt(encrypted); 10 11 return encrypted; 12 }
上面的代码通过将变量encrypted延后定义,避免了不被使用时仍需要耗费构造和析构的成本。但是第7和第8行的代码还有进一步改进的余地,第7行调用了一个默认构造函数,第8行调用了一个赋值构造函数,这两行代码可以通过调用一个拷贝构造函数来避免两次调用构造函数,如下所示:
string encrypted(pwd);
所以,将变量延后定义,具体的讲,是将变量延后至可以赋初值的时候再定义。
在循环语句中,是将变量定义在循环体外还是循环体内呢,即下面的代码哪一种更应该被选择呢:
Widget w; for(int i = 0; i < n; i++) { w = wts[i]; ... }
for(int i = 0; i < n; i++) { Widget w(wts[i]); ... }
从消耗成本上来讲,第一种:1个构造函数 + n个赋值函数 + 1个析构函数;第二种:n个构造函数 + n个析构函数。因此,如果一个构造函数加一个析构函数的成本要高于一个赋值函数的成本,那么第一种方式更合适,否则第二种方式更加合适。一般来讲,如果两者成本相当,那么优先选择第二个方式,因为第一种方式变量w覆盖的作用域更大,对程序的理解性和可维护性造成冲突。
以上整理自Effective C++中文版第三版 case 26。