一 谨记80-20法则:
(1)80-20法则:一个程序%80的资源用於%20的代码身上。
(2)当程序员努力提升软件性能的时候,如何找出瓶颈所在:
*大部分人采用的方法:猜。
*正确的方法:借助某个程序分析器。
二 考虑使用lazy evaluation(缓式评估):
(1)lazy evaluation:延缓运算,直到那些运算结果刻不容缓被迫切需要为止,如果一直不被需要,运算也就一直不执行。
(2)lazy evaluation的应用场合:
*Reference Counting(引用计数)。
*区分读和写。
*lazy fetching(缓式取出)。
*lazy expression evaluation(表达式缓式评估)。
三 分期摊还预期的计算成本:
(一)分期摊还预期的计算成本的方法:
1.caching:已经计算好而有可能再被需要的数值保留下来。
2.prefetching(预先取出):根据局部性原理和一次读一个大块数据比多次读小块数据效率高。
(二)优缺点(以空间换时间):
1.caching:会消耗过多内存,但可以降低那些“已被缓存的结果”的重新生成时间。
2.prefetching:需要一些空间放置被预先取出的东西,但可降低访问它们所需的时间。
四 了解临时对象的来源:
(一)临时对象:只要产生了一个non-heap对象,并且没有为它命名,便产生一个临时对象。
(二)来源:
1.pass by value(或pass by reference,但进行了隐式类型转换)。
*c++禁止为non-const reference参数产生临时对象。
2.函数返回对象的时候。
3.可以制造,在类型名称之后直接加小括号,如:type(参数)。
(三)总结:
1.临时对象可能很好成本,所以应该尽可能消除它们。
五 协助完成“返回值优化”:
1.有些函数必须返回对象,那么不要对它宣战,你无法消除它。
2.可以使用return constructor arguments以取代对象,从而让编译器把临时对象优化。
3.现在匿名对象和命名对象都可以借由return value optimization优化。
五 利用重载技术避免隐式类型转换:
*增加一大堆重载函数不见得是件好事,所以除非你有好的理由,使用重载函数后,程序的整体效率可获得重大改善。
六 考虑以操作符复合形式取代其独身形式:
(1)复合操作符比其对应的独身版本效率高,因为独身版本必须返回一个新对象,因此我们必须担负一个临时对象的构造和析构成本,至于复合版本则是直接将结果写入其左端自变量,所以不需要产生一个临时对象来放置返回值。
(2)以复合版本来实现独身版本,这样就只有复合版本需要维护.
(3)例如:+=和+.
七 考虑使用其他程序库:
*由于不同的程序库将效率、扩充性、移植性、类型安全性等的不同设计局限化,有时候可以找找看是否存在另一个功能相近的程序库而其在效率上有较高的设计权重。如果有,改用它,可大幅改善程序性能。
八 了解virtual functions、multipile inheritance、virtual base classes、runtime type identification的成本:
(一)virtual functions的成本:
1.必须为每一个拥有虚函数的class耗费一个virtual table的空间,其中条目就是该class的各个虚函数实现体的指针,其大小视虚函数的数量而定。每个class应该只有一个vtbl。
2.必须为每一个拥有虚函数的对象付出一个指针vptr的代价。
3.放弃inlining。
(二)多重继承的成本:
1.一个对象拥有多个vptrs(每个base class对应一个)。
2.虚拟继承的成本:常用实现手法利用指针指向virtual base class成分,以消除复制行为。
*扩充已存在的virtual table,以便维护每一个virtual base class的位置(gcc).
*导入一个virtual base class table.(vc6.0)
(三)RTTI的成本:
1.RTTI让我们在运行期间获得objects和class的相关信息,所以一定在某些地方存储那些信息——它们被存放在类型为type_info的对象内,可以通过typeid操作符取得某个class相应的type_info对象。
2.C++规范说:只有当一个class有至少一个虚函数时,才保证能够检验该对象的动态类型。
3.RTTI的成本:
*只需在每一个class的virtual table内增加一个条目,内含一个指针,指向“该vtbl所对应的class”相对应的type_info对象。
*再加上每个class所需的一份type_info对象的空间。