26、尽可能延后变量定义式的出现时间
(1)这样可以增加程序的清晰度并改善程序效率。如定义变量后还未使用遇到return或者抛出异常,这样未使用却增加了调用构造析构函数的成本。
27、尽量少做转型动作
(1)使用c++新式转型,而不要是用旧式转性。有四种新式转型:const_cast<T>()、dynamic_cast<T>()、reinterpret_cast<T>()和static_cast<T>()。const_cast将对象常量性转型;dynamic_cast执行安全向下转型;reinterpret_cast执行低级转型;static_cast强迫隐式转型。
(2)尽量避免转型,特别是在注重效率的代码中避免dynamic_cast。
(3)如果转型是必要的,试着将它隐藏于某个函数背后。客户随后可以调用该函数,而不需将转型放进他们自己的代码内。
28、避免返回handles指向对象内部
(1)handles(号码牌,用来取得某个对象),reference、指针和迭代器都是,而返回一个代表对象内部数据的handle,但会降低对象封装性。
(2)避免返回handles指向对象内部。遵守这个条款可以增加封装性,帮助const成员函数的行为像个const,并将发生虚掉号码牌的可能性降低。
29、为异常安全而努力是值得的
(1)异常安全函数即使发生异常也不会泄露资源或允许任何数据结构败坏。可以提供的保证分为三种:基本承诺、强烈保证和不抛掷保证。基本保证,保证异常被抛出后所有对象都处于前后一致的状态,但是现实状态不能保证;强烈保证,如果异常抛出,程序状态不改变,如果成功,则完全成功,如果失败就回到调用函数之前的状态;不抛掷异常,总能完成原来承诺的功能。
(2)强烈保证,往往能够以copy-and-swap实现出来,但是并非对所有函数都可实现或者具备现实意义。Copy-and-swap原则:为打算修改的对象(原件)做出一份副本,然后在那份副本上做一切必要修改,若有任何修改动作抛出异常,原对象仍然保持为改变状态;待所有改变都成功后,再将修改过的那个副本和原对象在一个不抛出异常的操作中置换。
(3)函数提供的异常安全保证通常最高只等于其调用之各个函数的异常安全保证中的最弱者。
30、透彻理解inlining的里里外外
(1)将大多数inline限制在小型、被频繁调用的函数身上。
(2)不要太热衷inline函数,inline函数是对每个函数都以函数本体替换之,会造成代码膨胀,也会导致额外的换页行为,降低指令高速缓存装置的击中率,以及伴随而来的效率损失。
(3)inline只是对编译器的一个申请,不是强制命令。这项申请可以隐喻也可以明确提出。如果成员函数或者friend函数定义于class内,则被隐喻为inline;template的具现化与inlining无关,如果不是具现的每个函数都是inline,则应避免将template声明为inline;大部分编译器拒绝将太过复杂的函数inline,对所有对virtual函数的调用也都会使inlining落空。
31、将文件间的编译依存关系降至最低
(1)支持“编译依存性最小化”的一般构想是:相依于声明式,不要相依于定义式。基于此构想的两个手段是Handle classes和interface classes。
(2)pimpl idiom手法(pimpl -- pointer to implementation),将所有“隶属对象的数据”从原对象放进另一个对象,然后赋予对象一个指针,指向那个所谓的实现对象。
(3)程序库头文件应该以“完全且仅有声明式”的形式存在,不管有无template都适用。