Modern C++ Design:官方十一章学习路线

按第一版官方结构梳理 Part I Techniques 4章与 Part II Components 7章,标出 Policy、traits、Typelist、lifetime、creation 和 dispatch 的依赖与现代迁移路线。

学习目标

  • 能按官方顺序解释 Part I 4章与 Part II 7章各自交付什么,并画出前置依赖
  • 能判断一个设计决定在 compile time、startup 还是 per call 才知道,从而选择 Policy、Factory、Functor、Visitor 或 Multimethod
  • 能把 Loki/C++98 实现迁移到现代标准设施,同时保留 ownership、compatibility、lifetime 与扩展方向的原始问题

为什么要按官方 11 章重建路线

第一版明确分成 Part I Techniques(第1-4章)与 Part II Components(第5-11章)。前者不是零散模板技巧,而是逐层建立设计语言:Policy 描述变化轴,compile-time techniques 提供检测/映射,Typelist 提供类型 schema 与 class generation,小对象分配器把这些思想放进真实内存状态机。

后七章每章造一个完整 component:Functor、SingletonHolder、SmartPtr、Object Factory、Abstract Factory、Visitor、Multimethods。它们同时包含 compile-time generation 与 runtime state;因此把本书概括成“全部零开销模板”会遗漏 type erasure、RTTI、registry、virtual dispatch 和 lifetime。

第一阶段:第1章先学变化轴

第1章从 do-it-all interface 与 inheritance matrix 失败出发,要求把独立变化原因拆成 Policies,由 Host 编排。它同时强调 enriched policy、destructor、incomplete instantiation、structure customization 和 incompatible combinations。

template<class Product,
         template<class> class Creation,
         class Lifetime,
         class Threading>
class Manager;

看到模板参数时先问:这些决定何时知道?若用户在运行中切换 creation mode,把它写成 Policy 会迫使 Manager type 变化;runtime strategy 更合适。Policy 不是默认答案,选择时机才是答案。

第二阶段:第2-3章建立元编程语言

第2章给出 static_assert 前身、partial specialization、local class、Int2Type、Type2Type、Select、convertibility detection、TypeInfo 与 Type Traits。第3章再把类型组成 sequence,执行 Length/TypeAt/Append/Erase/NoDuplicates/Replace/partial order,并生成 scatter/linear hierarchies。

using Products = TypeList<Button, Menu, Dialog>;
using Interface = GenScatterHierarchy<Products, AbstractFactoryUnit>;

这两章的现代语法已大幅改善:用 static_assert、concepts、std::type_traits、parameter packs、tuple/variant。但要保留三个问题:未选路径是否真的不实例化;type list 是否 unique/ordered;生成 hierarchy 的 layout、ABI、compile time 和 diagnostics 是否可接受。

第三阶段:第4章用 allocator 检验分层

第4章不是孤立性能技巧。Chunk、FixedAllocator、SmallObjAllocator 三层展示了“每层只拥有一个不变量”:Chunk 管 free blocks,FixedAllocator 管一个 size 的 Chunks,router 按 size 选 pool/fallback。

request(bytes)
  -> SmallObjAllocator bucket
  -> FixedAllocator available Chunk
  -> Chunk free-list pop

今天应先比较 std::pmr、mature malloc、monotonic arena;但 alignment、owner、lifetime、thread、retention 与 fallback 这些验收门没有过时。

第四阶段:第5-7章统一调用、生命周期和所有权

第5章 Functor 固定 signature、擦除 concrete callable;第6章 SingletonHolder 将 creation/lifetime/thread 变成 Policies;第7章 SmartPtr 将 storage/ownership/conversion/checking 拆开。三章分别回答“怎样调用”“对象活多久”“谁释放资源”。

Functor 并非纯 static abstraction,它通常有 indirect call 与 heap;Singleton 不是 static namespace,它有 dead reference/Phoenix/longevity;SmartPtr 的 atomic count 也不保证 pointee thread safety。读这一阶段要把方便 API 还原为 runtime cost 与 ownership graph。

第五阶段:第8-9章区分一个产品与一族产品

Object Factory 把 runtime ID 映射到 creator,适合 plugin/config 选择一个 concrete product;Abstract Factory 选择完整 compatible family,并由 ProductList 生成每产品 slots。两者可组合:先按 ID 选择 backend factory,再从该 family 创建 Buffer/Texture/Pipeline。

这阶段的真正难点是 duplicate/unknown key、returned owner、creator exception、registry lock、in-flight call、plugin unload 与 family snapshot,不是 map 的拼写。

第六阶段:第10-11章按动态类型选择操作

Visitor 用 Accept + Visit 两次 single dispatch,在稳定 element set 上扩展 operations;Multimethod dispatcher 按多个 dynamic arguments 的 type tuple 查 operation。前者通常是一元 element + operation object,后者可直接管理 (A,B) pairs。

编译期、启动期还是每次调用期

先预测:backend 在进程启动时从配置选择,内部 allocator policy 编译时固定,碰撞对象类型每 frame 变化。这三个决定不应都模板化,也不应都塞进 global registry。分别用 startup AbstractFactory、compile-time Policy、per-call Multimethod 能让 cost 与 evolution boundary 对齐。

现代 C++ 迁移矩阵

  • 手工 compile-time assertion/traits → static_assert、concepts、std::type_traits
  • 宏 Typelist/有限 arity → parameter packs、tuple、variant、fold expressions
  • Loki Functor → std::functionstd::move_only_function 或窄自定义 wrapper
  • Loki SmartPtr → unique_ptrshared_ptrweak_ptrspan/vector
  • 手工 Singleton threading → magic static、call_once,优先 dependency injection
  • 小对象 pool → std::pmr 或目标 allocator,按 workload 测量
  • RTTI wrapper → std::type_index;持久化仍用显式 schema ID
分步1 / 3

第一步:按官方顺序建立依赖

为每章写“输入技术、输出组件、runtime state、failure mode”;第5-11章必须能回指 Policy/traits/Typelist/allocator 中至少一个基础。

小结

  • 官方第一版是 Part I Techniques 4章与 Part II Components 7章,共11章,不是旧内容中的8个主题
  • Policy、compile-time techniques、Typelist 与 allocator 分层是后七章的设计语言和状态机基础
  • Functor/Singleton/SmartPtr 分别统一 call、global lifecycle 与 resource ownership
  • Object Factory 选一个 product,Abstract Factory 选一族 products;Visitor 与 Multimethod 处理不同 dynamic dispatch schema
  • 决定何时已知比“模板还是虚函数”更关键,compile/startup/per-call 应使用不同机制
  • 现代标准替代大量历史语法,但 compatibility、ownership、lifetime、unload 与 evolution contract 不会自动消失

练习

  1. 问题 1:为 11 章分组。 写出 Part I 四章与 Part II 七章,并说明第3章分别被第9、10章如何复用。
  1. 问题 2:按选择时机选机制。 压缩算法编译时固定,renderer 启动时配置,两个 scene objects 每 frame 交互;分别选择并说明。
  1. 问题 3:现代化一个 Loki 设计。 团队要把 SmartPtr/Typelist/Functor 全原样搬进 C++23,给出保留与替换清单。

名词解释

名词解释

本章出现的专业名词,用大白话再讲一遍。

Part I Techniques
第1-4章组成的 Policy、元编程、Typelist 与 allocator 技术基础。
Part II Components
第5-11章组成的 callable、lifetime、ownership、creation 与 dispatch 组件。
compile-time Policy axis
在构建类型时固定且可独立组合的设计变化轴。
compile-time type computation
以类型和常量为数据,经模板规则产生选择或新类型。
layered runtime component
将复杂状态机拆为 owner 清晰、协议狭窄的多层组件。
call-lifetime-ownership chain
从 callable 到 service 与 resource 都明确复制、销毁和线程域的契约链。
creation selection boundary
选择单产品 creator 或完整 product family 的两级创建边界。
dynamic dispatch schema
按一个或多个动态类型选择操作的结构与扩展契约。
semantic modernization
替换历史机制但保留原设计语义审计的现代化过程。

讨论

评论区加载中…