一. 内容
- 大多数情况下,适当提出你的 classes 定义和 function 声明,是花费心力最多的两件事。一旦正确完成它们,相应的实现大多直接了当。但是还是有些东西需要注意,我们将在之后的条款一一描述。
- 只要你定义了一个变量而其类型带有一个构造函数或析构函数,
当程序执行到这个变量定义式时,你便得承受构造成本,当这个变量离开作用域时,你便得承受析构成本
。即使这个变量并未使用
。 - 或许你认为你不会定义一个不使用的变量,但话不要说的太早。
看上面例子,加密函数在密码为空时会抛出异常,导致我们定义的变量 Encrypted 真的没被使用。也就是说该函数抛出异常后,你仍得付出 Encrypted 的构造成本和析构成本。所以最好延后 Encrypted 变量的定义式,直到确实需要它。class Password { public: static std::string Encrypt(const std::string& Password) { std::string Encrypted; if (Password.empty()) { throw std::logic_error("密码长度为零"); } //...加密过程 Encrypted=Password; return Encrypted; } };
- 但这段代码仍然不够好,因为 Encrypted 虽获定义却无任何实参作为初值。这意味调用的是其默认构造函数。条款4解释了为什么
通过默认构造函数构造出对象再赋值比直接在构造时指定初值效率差
。所以定义并初始化 Encrypted 的最佳方式是:
这让我联想起本条款所谓尽可能延后的真正意义。你class Password { public: static std::string Encrypt(const std::string& Password) { if (Password.empty()) { throw std::logic_error("密码长度为零"); } //...加密过程 std::string Encrypted(Password); return Encrypted; } };
不只应该延后变量的定义,直到非得使用该变量的前一刻,甚至尝试延后这份定义直到能够给它初值实参为止
。 - 对于循环怎么办呢?你可能感到疑惑,对于一个循环次数为n的循环体,可以把循环变量写在循环体外,也可以写在循环体内。前者代价为:
一个构造函数+一个析构函数+n个赋值操作
,后者代价为:n个构造函数+n个析构函数
。所以说如果 classes 的赋值操作效率比构造和析构成本高,就采用前者,否者采用后者。虽然一般前者效率比较高,但是注意写在循环体外会导致变量的作用域扩大,由此可能带来理解性和易维护性的下降。
二. 总结
- 尽可能延后变量定义式的出现。这样做可增加程序的清晰度并改善程序效率。