5.实现

Implementations #

26.Postpone variable definitions as long as possible #

std::string encryptPassword(const std::string& password)
{
    std::string encrypted;//默认构造
	encrypted = passwd;//赋值操作
    encrypt(encrypted);
    return encrypted;
}

更推荐下面的做法,更高效

std::string encryptPassword(const std::string& password)
{
    std::string encrypted(passwd);//copy构造
    encrypt(encrypted);
    return encrypted;
}
//1次构造,1次析构,n次赋值
Widget w;
for(int i = 0;i < n; ++i)
{
    w = ...
}

更推荐上面的做法,更高效

//n次构造,n次析构
for(int i = 0;i < n; ++i)
{
    Widget w;
    w = ...
}

27.Minimize casting #

优良的C++代码很少使用转型

宁可使用C++-style转型,不要使用旧式转型,前者很容易辨识出来

const_cast<T>( expression ) //将const转换为非const
dynamic_cast<T>( expression )//安全向下转型,用来决定某对象是否归属继承体系中的某个类型
reinterpret_cast<T>( expression )//低级转型,例如将int*转型为int
static_cast<T>( expression )//强迫隐式转换 例如将non-const对象转换为const对象,将int转换为double,将pointer-to-base转换为pointer-to-derived,将void*转换为typed指针

优点:

1、很容易在代码中被辨识出来 ,找出类型在哪个地点被破坏

2、转换动作的目标愈窄化,编译器愈能诊断出错误

在一个4层深的单继承体系内的某个对象身上执行dynamic_cast,每一次dynamic_cast会耗用多达4次的strcmp调用,用以比较class名称

28.Avoid retuning “handles” to object internals #

  • 对于内置类型,以及STL的迭代器和函数对象,使用pass-by-value更合适
  • C++编译器底层中的references往往是以指针方式实现的,意味着真正传递的是指针
  • 避免返回handles(包括references、指针、迭代器)指向对象内部

29.Strive for exception-safe code #

  • copy-and-swap 是对对象状态做出“全有或全无”改变的一个很好办法

  • “强烈保证”往往能够以copy-and-swap 实现出来,但是“强烈保证”并非所有函数 都可实现或具备现实意义

30.Understand the ins and outs of inlining #

  • inline函数背后的整体观念是,将“对此函数的每一个调用”都以函数本体替换之,这样做可能增加你的目标码(object code)大小

  • inline造成的代码膨胀亦会导致额外的换页行为(paging),降低指令高速缓存装置的击中率(instruction cache hit rate),以及伴随这些而来的效率损失

  • 如果inline函数的本体很小,编译器针对“函数本体”所产出的目标码可能 比针对“函数调用”所产生的目标码更小

  • inline在大多数C++程序中是编译期行为

  • inline只是一个申请,编译器可加以忽略,大部分编译器拒绝将太过复杂(例如带有循环或递归)的函数inlining

  • 所有对virtual函数 的调用,也都会使inlining落空,因为virtual意味着“等待,直到运行期才确定调用哪个函数”,而inline意味”执行前,先将调用动作替换为被调用函数的本体“。如果编译器不知道调用哪个函数 ,你就很难责备它们拒绝将函数本体inlining

  • 大多数编译器提供一个诊断级别:如果它们无法将你要求的函数inline化,会给你一个警告信息

  • 许多建置环境仅仅只能”在调试版本程序中禁止发生inlining“,毕竟你不能在一个并不存在的函数内设立断点

  • 一开始先不要将任何函数声明为inline,最后再找出有效增进程序整体效率的20%代码,然后将它inline或竭尽所能地将它瘦身

  • 将大多数inlining限制在小型、被频繁调用的函数身上

31.Minimize compilation dependencies between files #

  • 编译器必须在编译期间知道对象的大小

  • Handle classes 和 interface classes解除了接口和实现之间的耦合关系,从而降低文件间的编译依存性(compilation dependencies)

  • 支持”编译依存性最小化“的一般构想是:相依于声明式,不要相依于定义式

  • 程序库的头文件应该以”完全且仅有声明式“的形式存在