《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(编译时技术)

关键技法:

  1. Compile-Time Assertions(编译时断言):利用数组大小必须为正整数的特性实现静态检查

    #define STATIC_CHECK(expr) \
        typedef char static_check_##__LINE__[(expr) ? 1 : -1]
  2. Partial Template Specialization(部分模板特化):针对特定类型组合提供专用实现

  3. 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; };
  4. NullType/EmptyType:类型列表的空类型占位符

  5. 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()之前或之后访问导致未定义行为。

解决方案:

  1. Phoenix Singleton:延迟初始化,在第一次使用时创建
  2. 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实现为可直接使用的组件:

关键收获

  1. 策略模式是解耦的神器:将可变性提取为独立Policy,主类保持稳定
  2. 模板元编程是编译期的武器:TypeList、TypeTraits等工具让类型在编译期”思考”
  3. Generic Component的复用性:一次实现,处处可用,取代手写样板代码
  4. Loki的实践价值:书中的理论在Loki库中完整落地

与其他知识的关联

局限性

  • 出版于2001年,未覆盖C++11/14/17新特性(auto、lambda、move语义等)
  • 部分技巧在现代C++中已被标准库简化(如std::unique_ptr替代自定义智能指针)
  • 但核心思想(策略模式、泛型编程)历久弥新