《C++编程规范——101条规则、准则与最佳实践》笔记008

C++编程规范

C++ coding standards

Author
Herb Sutter 《Exceptional C++ Style》 《Exceptional C++》 《More Exceptional C++》
Andrei Alexandrescu 《Modern C++ Design》 Loki

设计风格(适用面比一个特定的类或者函数更广的原则和实践)

复杂性啊,愚人对你视而不见,实干家受你所累。有些人避而远之。惟智者能够善加消除。 ——Alan Perlis


我知道,但是却又忘记了Hoare的至理名言:不成熟的优化是程序设计中的万恶之源。 ——Donald Knuth

简单和清晰之间的平衡、避免不成熟的优化、避免不成熟的劣化,不仅适用于函数编写的层次,而且适用于类和模块设计权衡的更大范围,适用于更深的应用程序架构决策。
依赖性管理是软件工程的一个基础,任意选择一个优秀的软件工程技术,无论选择哪一个,它都是在想尽办法减少依赖性。
  • 继承?是为了使所编写的代码使用不依赖于实际派生类的基类。
  • 尽量减少全局变量?是为了减少因可见范围太大的数据所产生的远距离依赖。
  • 抽象?是为了消除处理概念的代码和实现它们的代码之间的依赖。
  • 信息隐藏?是为了使客户代码不依赖实体的实现细节。
依赖性管理的一个相关问题还反映在避免使用共享状态中,反映在应用信息隐藏,以及其他之中。
最有价值:第6条——正确、简单和清晰第一。

第8条 不要进行不成熟的优化

摘要

拉丁谚语,快马无需鞭策:不成熟优化的诱惑非常大,而它的无效性也同样严重。优化的第一原则就是:不要优化。优化的第二原则(仅适用于专家)是:还是不要优化。再三测试,而后优化。

讨论

不成熟的优化是万恶之源。——Donald Knuth
另一方面,我们不能忽视效率。——John Bentley

不成熟的优化:以性能为名,使设计或代码更加复杂,从而导致可读性更差,但是并没有经过验证的性能需求(比如实际的度量数据和与目标的比较结果)作为正当理由,因此本质上对程序没有真正的好处。毫无必要而且无法度量的优化行为其实根本不能使程序运行得更快。

让一个正确的程序更快速,比让一个快速的程序正确,要容易得太多、太多。

因此,默认时,不要把注意力集中在如何使代码更快上;首先关注的应该是使代码尽可能地清晰和易读。清晰的代码更容易正确编写,更容易理解,更容易重构——当然也更容易优化。使事情复杂的行为,包括优化,总是以后再进行的——而且只在必要的时候进行。
不成熟的优化经常并不能使程序更快:


  • 一方面,程序员在估计哪些代码应该更快或更小,以及代码中哪里会成为瓶颈上名声很臭。考虑一些事实,现代计算机都具有极为复杂的计算模型,经常是几个流水线处理单元并行工作,深高速缓存层次结构,猜测执行,分支预测……这还只是CPU芯片。在硬件之上,编译器也在尽其所能地猜测,将源代码转换成最能发掘硬件潜力的机器码。而在这些复杂的结构之上,还有“程序员的猜测”。所以,如果只是猜测的话,那些目标不明确的微观优化很难有机会显著地改善代码。因此,优化之前必须进行度量;而度量之前必须确定优化的目标。在需求得到验证之前,注意力应该放在头号优先的事情上——为人编写代码。(当有什么人要求你进行优化的时候,请进行需求验证。)

猜测执行,speculative execution,程序设计和计算机系统体系结构中的一种优化措施。在现代流水线微处理器中,使用猜测执行降低条件分支指令的代价。遇到条件分支指令时,处理器猜测最有可能转向的分支,并立即从此点开始执行。如果猜测不正确,此点之后的计算全部放弃。由于在下一指令知道之前,所涉及的流水线是休眠的,所以这种计算的代价很低。
  • 另一方面,在现代程序中,许多操作越来越不受CPU的限制。它们可能更受内存的限制、网络的限制、硬盘的限制,需要等待Web Service,或等待数据库。即使在最好的情况下,优化这些操作的应用程序代码,也只不过能使等待操作更快。这也意味着程序员浪费了宝贵的时间去改善没有必要改善的地方,却没有进行必要的有价值的改善。
  • 当然,迟早需要优化某些代码。首先要考虑算法优化,并尝试将优化封装和模块化,然后在注释中清楚地说明优化的原因并列出所用算法作为参考。
    初学者常犯的一个错误,就是编写新代码时着迷于进行过度优化(而且充满自信),却牺牲了代码的可理解性。这常常会产生大杂烩代码,这种代码即使开始时是正确的,也非常难以阅读和修改。
    通过引用传递,优先调用前缀形式的++和–,和使用很自然地从指尖流出的惯用法,都不属于不成熟的优化。这些都不是不成熟的优化,而是在避免不成熟的劣化。

    示例

    inline悖论(不成熟的微观优化所带来的隐性代价)

    分析器(profiler)能够通过函数的命中计数出色地告诉我们哪些函数应该但是没有标记为inline;然而,分析器在寻找哪些已经标记为inline但是不应该标记方面,却极不擅长。太多的程序员习惯以优化的名义“将inline作为默认选择”,这几乎总是以更高的耦合性为代价,而换来的好处到底如何却很可疑。

    你可能感兴趣的:(C++编程规范)