《Modern C++ Design》- Andrei Alexandrescu
核心思想
本书开创了泛型编程与设计模式结合的新范式,提出了Generic Component概念——可复用的设计模板,为编译器生成样板代码。核心理念:用模板替代继承层级,用策略模式替代硬编码行为。
全书结构
Part I: Techniques(技术基础)
Chapter 1: Policy-Based Class Design(基于策略的类设计)
核心问题:Do-It-All Interface(全能接口)失败——接口膨胀导致大量不需要的功能被继承。
解决方案:将类的不同关注点分解为独立的Policy Class,通过模板组合:
- 每个Policy封装一个独立的设计决策(如内存分配、线程安全、异常处理)
- 默认Policy提供合理行为,用户可选覆盖
- 策略之间相互独立,可任意组合
关键概念:
- Enriched Policies:包含嵌套类型定义的策略(如
LockingMechanism::MutexType) - Incomplete Instantiation:利用未实例化模板实现可选功能
- Compatible/Incompatible Policies:策略间的兼容性约束
示例:
template <
typename ThreadSafetyPolicy,
typename ExceptionPolicy,
typename MemoryPolicy
>
class MyContainer : public ThreadSafetyPolicy,
public ExceptionPolicy,
public MemoryPolicy {
// ...
};Chapter 2: Techniques(编译时技术)
关键技法:
-
Compile-Time Assertions(编译时断言):利用数组大小必须为正整数的特性实现静态检查
#define STATIC_CHECK(expr) \ typedef char static_check_##__LINE__[(expr) ? 1 : -1] -
Partial Template Specialization(部分模板特化):针对特定类型组合提供专用实现
-
Type Selection:基于编译时条件选择类型
template <bool cond, typename T, typename F> struct Select { typedef T Result; }; template <typename T, typename F> struct Select<false, T, F> { typedef F Result; }; -
NullType/EmptyType:类型列表的空类型占位符
-
Type Traits:检测类型属性的模板(如
is_pointer、is_array)
Chapter 3: Typelists(类型列表)
核心数据结构:
typedef Typelist<int, Typelist<char, NullType>> MyTypeList;关键操作:
Length<Typelist>:计算类型数量TypeAt<Typelist, N>:按索引获取类型Find<Typelist, T>:查找类型位置Append<Typelist, T>:追加类型Eraser<Typelist, T>:删除指定类型Reverse<Typelist>:反转类型列表
应用:类型元编程的基础设施,支持任意数量的类型参数。
Chapter 4: Small-Object Allocation(小对象分配器)
问题:频繁分配/释放小对象导致内存碎片和性能下降。
解决方案:Chunk-based Allocator
- 将内存划分为固定大小的chunk池
- 小对象直接从chunk分配,无需系统调用
- 对象析构时归还到chunk而非释放到堆
性能优势:O(1)分配/析构,缓存友好,减少碎片。
Part II: Components(通用组件实现)
Chapter 5: Generalized Functors(通用函数对象)
目标:统一封装所有可调用实体(函数指针、成员函数指针、functor对象),提供一致的调用接口。
关键挑战:
- 不同调用实体的签名差异
- 参数类型转换和返回值处理
- 指针成员函数的间接调用
解决方案:使用辅助模板进行转发和类型推导。
Chapter 6: Implementing Singletons(单例模式)
问题:传统单例存在”初始化顺序故障”和”析构顺序故障”。
Dead Reference Problem:静态对象在main()之前或之后访问导致未定义行为。
解决方案:
- Phoenix Singleton:延迟初始化,在第一次使用时创建
- Singleton with Longevity:控制单例生命周期,确保正确析构
template <typename T>
class SingletonHolder {
public:
static T& Instance() {
static T instance;
return instance;
}
private:
SingletonHolder() {}
};Chapter 7: Smart Pointers(智能指针)
设计目标:提供类似原生指针的接口,但自动管理内存。
关键策略:
- 引用计数:共享所有权
- 独占所有权:唯一所有者
- 引用计数 + 循环检测:支持双向引用
Operator Overloading:
operator*,operator->:解引用operator==,operator!=:比较operator<:排序(用于STL容器)
线程安全:可选的锁机制嵌入智能指针。
Chapter 8: Object Factories(对象工厂)
问题:如何用类型安全的方式创建对象?
解决方案:注册-创建分离模式
- Factory:管理注册和创建逻辑
- Creator:封装对象创建细节
typedef Factory<int, BaseClass> MyFactory;
MyFactory::Register(int_id, &Creator<MyDerivedClass>);
BaseClass* obj = MyFactory::Create(int_id);Chapter 9: Abstract Factory(抽象工厂)
扩展:支持多产品族的工厂模式。
- AbstractFactory:定义创建接口
- ConcreteFactory:实现具体产品族的创建
Chapter 10: Visitor(访问者模式)
问题:如何在保持类型安全的同时实现双分派?
解决方案:
- Acyclic Visitor:避免虚函数循环依赖
- Visitor with Type Registration:运行时类型识别 + 分派
Chapter 11: Multimethods(多方法)
核心概念:支持多个参数类型的分派(超越虚函数的单分派)。
实现方式:Double Switch-on-Type + 类型注册表。
Loki库
作者配套发布了Loki开源库,将书中所有Generic Component实现为可直接使用的组件:
- 网址:http://www.lokigames.com/loki/
- 包含:智能指针、单例、工厂、Visitor、Functor等完整实现
关键收获
- 策略模式是解耦的神器:将可变性提取为独立Policy,主类保持稳定
- 模板元编程是编译期的武器:TypeList、TypeTraits等工具让类型在编译期”思考”
- Generic Component的复用性:一次实现,处处可用,取代手写样板代码
- Loki的实践价值:书中的理论在Loki库中完整落地
与其他知识的关联
- Effective Modern C++:Scott Meyers对现代C++的42条指南,与本书的模板技术互补
- Cpp-Coding-Standards-101条编码规范:Herb Sutter的编码规范,Policy-Based Design是其核心推荐
- Functional-Programming-in-C++:FP风格与Loki的Functor体系高度契合
局限性
- 出版于2001年,未覆盖C++11/14/17新特性(auto、lambda、move语义等)
- 部分技巧在现代C++中已被标准库简化(如
std::unique_ptr替代自定义智能指针) - 但核心思想(策略模式、泛型编程)历久弥新