当你谨慎的设计出 classes (template) 和 function template 之后, 你依旧应该注意一些细节上的东西.
- 条款26: 太早的定义变量可能会导致效率上的拖延
- 条款27: 过度的使用转型,可能导致代码变慢,难以维护,以及难以理解的错误
- 条款28: 返回对象的内部数据的 handles ,可能会破坏封装,并留下 危险的handles
- 条款29: 未考虑异常则可能导致资源的泄漏和数据的败坏
- 条款30: 过度的 使用inline 可能引起代码的膨胀
- 条款31: 过度的耦合则可能导致让人不满意的冗长建置时间(build times)
26.尽可能的延后变量定义式的出现时间
一旦你定义了一个变量,你就的为它付出代价.
1 | int encrytPassword(const string& password) { |
传入的密码即使是空串,你依旧得付出 encrypted 的构造成本和析构成本,最好延后 encrypted 的定义式,直到确实需要它.
1 | int encrytPassword(const string& password) { |
现在,你需要付出 default 构造函数,进行赋值,析构的成本. 而条款4曾指出 “通过default 构造函数构造出一个对象然后对它赋值” 比 “直接在构造时指定初值” 效率差.
因此更好的代码是跳过无意义的 default 构造过程.
1 | int encrytPassword(const string& password) { |
“竟可能延后”的真正意思是: 你不只应该延后变量的定义,直到非得使用该变量的前一刻为止,你还应该延后这份定义直到能够给它初值实参为止.
1 | // 方法A: 定义于循环外 |
我们现在来比较这两种方法:
方法A: 需要付出 1个构造函数 + 1个析构函数 + n 个 赋值操作
方法B: n个构造函数 + n 个 析构函数
如果 clases 的 一个赋值成本低于一个 构造+ 析构 成本,方法A更为高效(当 n 较大时,方法A更优).
27.尽量少做转型动作
C++ 总共提供六种形式的转型操作,其中包括两种 “旧式转型” 和四种 “新式转型”.
1 | /*旧式转型*/ |
28. 避免返回 handles 指向对象内部成分
1 | class Point{ |
上面的代码返回了 Point 的引用,这实际上是自相矛盾的,函数被声明为 const,但调用者却依旧能够使用返回的 reference 修改成员变量.
同样的情况发生在指针,迭代器身上
1 | //将代码更改为这样是一个好选择吗? |
上面的方案一是昂贵的时间消耗,而方案二可能带来 dangling handles 问题.
29. 考虑 “出现异常”的情况
30. inlining
当你使用 inling 函数时, 你可以调用它们又不需要承担函数调用所招致的额外开销.除此之外,编译器还可能会对它进行特别优化.
但是,且慢,不要过度的使用 inlining ,这会造成程序体积的增大,导致频繁的换页行为,较低高速缓存的集中率.
1 | class Person{ |
例外,记住: inline 只是对编译器提出申请,并不是一个强制命令