《Effective C++》读书笔记第五章——实现(Implementations)

本文探讨了C++编程中的关键原则,包括延后变量定义、减少类型转换、避免内部对象暴露、追求异常安全性、理解内联机制、最小化编译依赖等,旨在提升代码质量与效率。

条款26:尽可能延后变量定义式的出现时间

(Postpone variable definitions as long as possible)

  • 尽可能延后变量定义式的出现。这样做可增加程序的清晰度并改善程序效率。
    eg:你不只应该延后变量的定义,直到非得使用该变量的前一刻为止,甚至应该尝试延后这份定义直到能够给它初值实参为止。 如果这样,不仅能够避免构造(和析构)非必要对象,还可以避免无意义的默认构造行为。

条款27:尽量少做转型动作

(Minimize casting)

  • ==如果可以,尽量避免转型,特别是在注重效率的代码中避免dynamic_casts。==如果有个设计需要转型动作,试着发展无需转型的替代设计。
    eg:
    在派生类中调用基类方法:
    // 错误,调用的是“当前对象之基类成分”的副本,如果其修改了对象内容,实际只修改了副本
    static_cast< Window >(*this).onResize();
    // 正确
    Window::onResize();
  • 如果转型是必要的,试着将它隐藏于某个函数背后。 客户随后可以调用该函数,而不需将转型放进他们自己的代码内。
  • 宁可使用C++ style(新式)转型,不要使用旧式转型。 前者很容易辨识出来,而且也比较有着分门别类的职掌。
    eg:
    1、旧式转型:
    (T)expression // C风格,将expression转型为T
    T(expression) // 函数风格,将expression转型为T
    2、新式转型:
    const_cast< T >(expression) // 常量性转除
    dynamic_cast< T >(expression) // 安全向下转型
    reinterpret_cast< T >(expression) // 意图执行低级转型,实际动作(及结果)可能取决于编译器
    static_cast< T >(expression) // 强迫隐式转换

条款28:避免返回handles指向对象内部成分

(Avoid returning “handles” to object internals)

  • 避免返回handles(包括references、指针、迭代器)指向对象内部。遵守这个条款可增加封装性,帮助const成员函数的行为像个const,并将发生“虚吊号码牌”(dangling handles)的可能性降至最低。

条款29:为“异常安全”而努力是值得的

(Strive for exception-safe code)

四十年前,满载goto的代码被视为一种美好实践,而今我们却致力写出结构化控制流(structured control flows)。二十年前,全局数据(globally accessible data)被视为一种美好实践,而今我们却致力于数据的封装。十年前,撰写“未将异常考虑在内”的函数被视为一种美好实践,而今我们致力于写出“异常安全码”。时间不断前进。我们与时俱进!

  • 异常安全函数(Exception-safe funcitons)即便发生异常也不会泄漏资源或允许任何数据结构败坏。这样的函数区分为三种可能的保证:基本型、强烈型、不抛异常型。
  • “强烈保证”往往能够以copy-and-swap实现出来,但“强烈保证”并非对所有函数都可实现或具备现实意义。
  • 函数提供的“异常安全保证”通常最高只等于其调用之各个函数的“异常安全保证”中的最弱者。

条款30:透彻了解inlining的里里外外

(Understand the ins and outs of inlining)

  • 将大多数inlining限制在小型、被频繁调用的函数身上。这可使日后的调试过程和二进制升级(binary upgradability)更容易,也可使潜在的代码膨胀问题最小化,使程序的速度提升机会最大化。
    eg:
    1、inline函数背后的整体观念是,将“对此函数的每一个调用”都以函数本体替换之。这样做可能增加目标码(object code)大小。在一台内存有限的机器上,过度热衷inlining会造成程序体积太大(对可用空间而言)。即使拥有虚内存,inline造成的代码膨胀亦会导致额外的换页行为(paging),降低指令高速缓存装置的击中率(instruction cache hit rate),以及伴随这些而来的效率损失。
    2、inlining在大多数c++程序中是编译器行为。
    3、一个表面上看似inline的函数是否真是inline,取决于你的建置环境,主要取决于编译器。幸运的是大多数编译器提供了一个诊断级别:如果它们无法将你要求的函数inline化,会给你一个警告信息。
    4、
    inline void f() {…} //假设编译器有意愿inline“对f的调用”
    void (*pf)() = f; //pf指向f

    f(); // 这个调用将被inlined,因为它是一个正常调用。
    pf(); // 这个调用或许不被Inlined,因为它通过函数指针达成。
  • 不要只因为function templates出现在头文件,就将他们声明为inline。

条款31:将文件间的编译依存关系降至最低

(Minimize compilation dependencies between files)

  • 支持“编译依存性最小化”的一般构想是:相依于声明式,不要相依于定义式。基于此构想的两个手段是Handle classes和Interface classes。
  • 程序库头文件应该以“完全且仅有声明式”(full and declaration-only forms)的形式存在。这种做法不论是否涉及templates都适用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值