Skip to content

Latest commit

 

History

History
62 lines (48 loc) · 2.58 KB

File metadata and controls

62 lines (48 loc) · 2.58 KB

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

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

考虑下面这个函数,它计算通行密码的加密版本而后返回,前提是密码够长。如果密码太短,函数会抛出异常,类型为logic_error:

// 这个函数过早定义变量 encrypted
std::string encryptPassword(const std::string& password) {
  using namespace std;
  string encrypted;
  if (password.length() < MininumPasswordLength) {
    throw logic_error("Password is too short");
  }
  ...
  return encrypted;
}

如果有个异常被抛出,对象encrypted在此函数中没有被使用。也就是说如果函数抛出异常,你就得付出encrypted的构造和析构成本。所以最好延后encrypted的定义式,直到确实需要它:

std::string encryptPassword(const std::string& password) {
  using namespace std;
  if (password.length() < MininumPasswordLength) {
    throw logic_error("Password is too short");
  }
  string encrypted;
  ...
  return encrypted;
}

encrypted虽或定义却无任何实参作为初值。这样就会造成默认构造函数和赋值操作两个步骤,效率比直接调用有参构造低。举个例子,假设encryptPassword的艰难部分在以下函数中进行:

void encrypt(std::string& s);

于是encryptPassword可实现如下,虽然还不是最好的做法:

std::string encryptPassword(const std::string& password) {
  ...
  std::string encrypted(password); // copy constructor
  encrypt(encrypted);
  return encrypted;
}

你不只应该延后变量的定义,直到非得使用该变量的前一刻为止,甚至应该尝试延后这份定义直到能够给它初值为止。如果这样,不仅能够避免构造非必要对象,还可以避免无意义的默认构造行为。

如果变量只在循环内使用,那么把它定义于循环体外还是循环体内?

  • A:定义在循环外:1个构造函数+1个析构函数+n个赋值操作
  • B:定义在循环内:n个构造函数+n个析构函数

除非你知道赋值成本比构造+析构低,或你正在处理代码中的效率高度敏感的部分,否则你应该使用做法B。

请记住

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