今天早上在 O'Reilly 上偶然发现 Scott Meyers 的《Effective Modern C++》正在做半价活动,已经是最后一天了,就赶紧趁打折的机会收了这本书的 Early Release 版。接下来这段时间,我会把某些章节的快速记录整理一下,作为一个系列不定期地发在俺的 blog 上。

出于下面两个因素的考虑,我不会按原文逐字句译,而只会概括性地表述原文的思路和(必要情况下)我的理解。

  1. 这本书还处在 "pre-publication draft" 状态,其中的内容成书时可能会被微调。
  2. 逐字句译是个体力活,从个人角度讲其实不是分配精力的最优方式(懒人找起借口真是信手拈来:P)

想看精确原文的同学建议买一本,或等国内翻译(考虑到 Scott Meyers 之前发的 《Effective C++》(EC)《More Effective C++》(MEC) 的热门程度,我想国内很快就会有完全版的译文出版)。


标题中的 [EMC] 是书名的首字母缩写,目的是方便脚本自动地将相关的 markdown posts 编为一个系列(见大纲页面),后面如果有系列性的 posts 会沿袭此法,不再另行说明。

下面的内容是这本书的介绍部分(Introduction)。正如上面提到的,一些具体内容我已做过删节,如有影响阅读的跳跃或疏漏,请在评论中指出,谢谢 :)


EMC - Introduction

有经验的程序员接触 C++11 时会发现多了不少东西。auto / ranged-for / lambda/ rvalue 等功能,和对并发 (Concurrency) 的支持,改变了 C++ 的样貌。一些惯用法也变了,比如 空指针(nullptr) / 别名 (alias declaration) / 有作用域的枚举 (scoped-enum) / 智能指针等等。

但比“熟悉和了解这些新特性”更重要的是——怎样合理而灵活地运用它们。毕竟新特性的介绍网上一搜一大把,但那些谈到“如何在实际的工程环境中有效地 (Effectively) 运用”的信息,就难找得多了。这就是本书的主要内容——对于新特性,不做照本宣科的描述,而重点讲解其在实践中的运用方法。

正如前面提到的 EC 和 MEC,EMC 也是采用条款形式,共 42 条(这样可以有效保持条款间的独立性)。下面列举了部分涉及的范围:

  • 各种类型推导的方式
  • 什么时候应该(不该)用 auto?
  • 为什么要保证 const 方法的线程安全?
  • 怎么用 std::unique_ptr 实现 Pimpl 惯用法?
  • 为什么在 lambda 表达式中要避免使用默认捕获模式?
  • std::atomic 和 volatile 有啥区别?
  • 等等。

书中以条款形式回答了这些问题。值得注意的是,这些内容全部是“符合标准”且“平台无关”的可移植 C++ (Portable C++)。

这些条款以指导和参考(而非规则)的形式列出,这就意味着也有例外的存在。我们不仅需要关注条款给出的建议,更应关注其背后的基本思路,这样有助于判断“某种特殊的情形是否正对应着一个例外”的情况。本书的目标不是提供一堆“该做什么不该做什么”的教条,而是传达对于 C++11/14 的运行机制的较深层次理解。


术语和约定

这一节简要说明了一下书中会涉及到的一些术语。

首先说明了书中提到 C++ 的不同版本时所指代的含义:

  • 当提到 C++98 时,实际上指的是 C++98 和 C++03 (因为 03 只是一个相对小的修订)
  • 当提到 C++11 时,实际上指的是 C++11 和 C++14 (因为 14 只是一个相对小的修订)
  • 当提到 C++ 时,实际上指的是所有的版本

[GL] 说明一下,下面加粗的小标题是我另拟的,方便厘清行文结构,原文无。


关于 move 和 rvalue

C++11 的诸多特性中,应用最普遍的也许是 move 语义了,而 move 语义的基础是辨别右值 (rvalue,可 move) 和左值 (lvalue,不可 move)。判断表达式是否是左值,有一个简单的办法,就是看看能否取它的地址,能取地址的就是左值。这个办法有一个额外的好处,就是能提醒你,对一个特定的表达式而言,它的类型 (expression type) 跟“它是左值还是右值”是无关的。这一点的一个重要引申是,若一个函数 Foo 的参数 val 是类型 T 的右值引用(通常以 T && val 的形式出现),并不会影响“这个参数 val 本身是一个左值”这个事实——正如前面提到的,在 Foo 函数内部,可以自由地取 val 的地址。

代码示例:

class Widget { 
public: 
  Widget(Widget&& rhs);    // rhs 是左值, 虽然它有一个右值引用类型
                          
};  

关于辨别迁移构造 (move-construction) 和拷贝构造 (copy-construction)

[GL] 在中文语境下“move”相关的术语尚未有合适的译名,此处若中英混杂(如“move构造”)则略嫌生硬且影响理解,于是暂以“迁移”代之,见谅。如有更好的表达方式,还请不吝赐教。

如果一个对象 A 是由相同类型的另一个对象 B 构造而来,不论构造方式是迁移构造 (move-constructed) 还是拷贝构造 (copy-constructed) 都被认为是对象的复制 (object copy)。C++ 目前还没有专门的术语,用于区分迁移构造的对象复制 (move-constructed copy) 和拷贝构造的对象复制 (copy-constructed copy)。

代码示例:

void someFunc(Widget w);

Widget wid;
                    
someFunc(wid);                              
someFunc(std::move(wid)); 

上面的示例中,someFunc 被调了两次,第一次是拷贝构造,第二次是迁移构造。这个例子说明了一点——同一个参数类型的函数,以不同的方式调用,开销是不同的。仅仅查看被调用方的参数列表,是无法知道实际调用发生时参数传递的开销的。当然了,迁移未必一定就比复制快,还要看具体实现而定。


关于完美转发 (perfect-forwarding) 异常安全 (exception-safe) 函数对象 (function object) 和匿名函数 (lambda and closure)

[GL] 这些基本概念,相信读到这里的同学都不会有什么疑问,就不详细说了。

需要简单说一下的是异常安全分为基本保证 (basic-guarantee)强保证 (strong-guarantee)。其中前者是指:

当异常被抛出时,对应情境下的不变量应该在有效状态(也就是不能有 corrupted data structure),也没有任何外部的资源被泄漏。

而后者是指:

当异常被抛出时,程序的状态能保持跟调用函数之前完全一致([GL]也就是“零副作用”)。

「注」不变量 [invariants](http://en.wikipedia.org/wiki/Invariant_(computer_science%29), 此处还包括 Class Invariant


关于声明和定义的辨析 (declaration / definition) 函数签名 (function signature) 待移除特性 (deprecated feature) 和未定义行为 (undefined behavior)

[GL] 这些也都不展开说了。

  • 声明和定义的区分属于基本内容,此处不再赘述。
  • 函数签名的详细讨论可见俺的前一篇文章
  • 待移除特性如 std::auto_ptr,移除原因不再赘述。
  • 未定义行为是 C/C++ 特有的性能优先的产物。虽然理论上编译器在这些情况下可以做任何事,但实际上遇上这些情况编译期通常的选择是啥也不干,该怎么样就怎么样。

其它细节略。


Gu Lu


[2014-09-10] Update: 文中的大纲页面的链接失效已修复,点击这里可以访问。

Comments
Write a Comment

Tags

随笔   游戏开发   Bitcoin   Programming   C/C++   优化   Unity   C++   区块链   知乎   BSV   游戏设计   中国文化   比特币   Unity3D   软件开发   引擎设计   系统架构   Production   idtech   Bitcoin SV   加密货币   项目管理   游戏评论   资源管理   资源流水线   效率   道德经   网络   方法论   模板编程   Blockchain   Lua   Blockchain Computing   Oculus   GDC   渲染   VR   PerfAssist   BitcoinSV   Unity MemoryProfiler   BCH   读书笔记   经济学   信息过载   行业报告   字体   Productivity   图形   网络编程   Dice   协程   EMC   Premake   万物理论   测试   中间件   SatoPlay   Game Engine   新手引导   区块链游戏   Methodology   CI   命令行解析   Science   goroutine   ndk   Ethereum   nanomsg   自动化   Scripting   摘录   Debugging   同步技术   cppcon   C++模板   数据上链   DOOM3   技术评估   Unity GC   C++11   学习方法   Surface Pro 3   Engine Evaluation   CRT   文化   笔记   golang   图形编程   多线程   ETH   Bitcoin Cash   cppcon14   Visual Studio   Unity Coroutine   跨语言可变参数列表   团队协作   货币   Deployment   Visual Assist   工程改进   Michael Abrash   exp   开放世界   权利   量子计算   域名   虚拟现实   系统重构   slua   遮挡剔除   完美转发   协作式调度   Modern C++   Money   类型推导   Memory Debugging   个人成长   小故事   BTC   暴雪   产品   历史   错误处理   Unity Profiler   MOD  

知识共享许可协议
本作品由Gu Lu创作,采用知识共享Attribution-NonCommercial-NoDerivatives 4.0 国际许可协议进行许可。