Effective C++条款26:实现之(尽可能延后变量定义式的出现时间)
原创
©著作权归作者所有:来自51CTO博客作者董哥的黑板报的原创作品,请联系作者获取转载授权,否则将追究法律责任
一、变量定义的成本
-
只要你定义一个变量,该变量带有构造函数与析构函数,那么:
- 当你定义这个变量时就要执行它的构造函数
- 变量生命周期结束后就要执行他的析构函数
二、尽量延迟变量定义的时间
- 变量定义需要执行构造与析构函数,因此在某些情况下为了提高程序的效率,应该延迟变量定义的时间。请看下面的演示案例:
演示案例
- 下面定义一个函数,用来对密码进行加密,如果参数传入的密码过段就抛出一个logic_error异常(见条款54)
//参数:要加密的密码
//返回值:加密后的密码
std::string encryptPassword(const std::string& password)
{
using namespace std;
string encrypted; //定义的临时变量
if (password.length()<MinimumPasswordLength) {
throw logic_error("Password is too short");
}
//...
return encrypted;
}
- 上面我们定义了一个临时变量encrypted,但是如果函数执行到if的时候程序抛出了异常,那么你就需要承担encrypted变量的构造与析构函数(但是我们没有完全用到这个变量),因此为了提升效率,我们应该延迟变量encrypted的定义
//参数:要加密的密码
//返回值:加密后的密码
std::string encryptPassword(const std::string& password)
{
using namespace std;
if (password.length()<MinimumPasswordLength) {
throw logic_error("Password is too short");
}
string encrypted; //在异常的后面定义
//...
return encrypted;
}
三、以直接构造代替变量的默认构造函数
- 上面我们的变量encrypted使用的是默认的构造函数,在条款4中我们说过“通过默认的构造函数构造对象”比“直接在构造时指定初值”的效率差。因此我们应该避免变量定义时使用默认的构造函数
演示案例
- 下面我们定义的变量encrypted使用默认构造函数,然后再以拷贝辅助运算符将参数赋值给它
//参数:要加密的密码
//返回值:加密后的密码
std::string encryptPassword(const std::string& password)
{
using namespace std;
if (password.length()<MinimumPasswordLength) {
throw logic_error("Password is too short");
}
string encrypted; //使用默认的构造函数
encrypted=password; //然后再使用拷贝赋值运算符进行赋值
//...
return encrypted;
}
- 上面的效率比较低, 因此我们建议在变量定义时直接构造
//参数:要加密的密码
//返回值:加密后的密码
std::string encryptPassword(const std::string& password)
{
using namespace std;
if (password.length()<MinimumPasswordLength) {
throw logic_error("Password is too short");
}
string encrypted(password); //使用拷贝构造函数
//...
return encrypted;
}
四、有循环时变量何时定义?
//方法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个析构函数
- 如果类的赋值成本低于一组构造+析构,那么做法A可选,尤其当n值很大的时候;否则做法B比较好
- 做法A中w的作用域更大,如果与程序的可理解性或易维护性造成冲突的话,选择B比较好
五、总结
- 尽可能延后变量定义式的出现。这样做可增加程序的清晰度并改善程序效率