Item 26:尽可能延后变量定义式的出现时间

0.概述

尽可能延后变量定义式的出现。这样做可增加程序的清晰度并改善程序效率。

延后的真正含义有2:

  1. 延后变量的定义,直到非得使用该变量的前一刻为止;
  2. 延后变量的定义,直到能够给它初值实参为止。

1. 第一层含义

1.1 不推荐做法举例

只要你定义了一个变量而其类型带有一个构造函数或析构函数,那么当程序的控制流(control flow)到达这个变量定义式时,你便得承受构造成本;当这个变量离开其作用域时,你便得承受析构成本。即使这个变量最终并未被使用,仍需耗费这些成本,所以应该尽可能避免这种情形。

// this function defines the variable "encrypted" too soon
std::string encryptPassword(const std::string& password)
{
    using namespace std;
    string encrypted;
    if (password.length() < MinimumPasswordLength) {
        throw logic_error("Password is too short");
    }
    ... // do whatever is necessary to place an
    // encrypted version of password in encrypted
    return encrypted;
}

过早定义encrypted,如果抛出异常,就不会被使用,但是依然付出了构造和析构成本

1.2 推荐做法举例

// this function postpones encrypted’s definition until it’s truly necessary
std::string encryptPassword(const std::string& password)
{
    using namespace std;
    if (password.length() < MinimumPasswordLength) {
        throw logic_error("Password is too short");
    }
    string encrypted;
    ... // do whatever is necessary to place an
    // encrypted version of password in encrypted
    return encrypted;
}

延后encrypted的定义直到真的使用它

2.第二层含义

1.2中的代码虽然有定义但却没有任何实参作为初值。

条款4曾解释为什么“通过default构造函数构造出一个对象然后对它赋值”比“直接在构造时指定初值”效率差。也适用于这里

2.1 不推荐做法举例

// this function postpones encrypted’s definition until
// it’s necessary, but it’s still needlessly inefficient
std::string encryptPassword(const std::string& password)
{
    ... // import std and check length as above
    string encrypted; // default-construct encrypted
    encrypted = password; // assign to encrypted
    encrypt(encrypted);
    return encrypted;
}

2.2 推荐做法举例

以password作为encrypted的初值,跳过无意义的默认构造过程:

// finally, the best way to define and initialize encrypted
std::string encryptPassword(const std::string& password)
{
    ... // import std and check length
    string encrypted(password); // define and initialize via copy
    // constructor
    encrypt(encrypted);
    return encrypted;
}

3. 循环怎么办?

下面有两种可能的做法:

planA:

//方法A:定义于循环外
Widget w;
for (int i = 0; i < n; ++i){
    w=取决于i的某个值;
}

planB:

//方法B:定义于循环内
for (int i = 0; i < n; ++i){
widget w(取决于i的某个值);
}

以上两种写法的成本如下:

  • 做法A:1个构造函数+1个析构函数+n个赋值操作
  • 做法B: n个构造函数+n个析构函数

如果classes的一个赋值成本低于一组构造+析构成本,做法A大体而言比较高效。尤其当n值很大的时候。否则做法B或许较好。

此外做法A造成名称w的作用域(覆盖整个循环)比做法B更大,有时对程序的可理解性和易维护性造成冲突。

总结:除非(1)知道赋值成本比“构造+析构”成本低,(2)你正在处理代码中效率高度敏感(performance-sensitive)的部分,否则应该使用做法B。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值