Skip to content

对象模型与内存布局实现分析

C++ 对象模型定义了对象在内存中的布局方式。本文分析 GCC 和 LLVM 的对象模型实现。


一、核心概念

1.1 对象内存布局

对象内存布局:

简单类:
┌─────────────────────────────────────┐
│ 成员变量 1                          │
├─────────────────────────────────────┤
│ 成员变量 2                          │
└─────────────────────────────────────┘

带虚函数的类:
┌─────────────────────────────────────┐
│ vptr(虚函数表指针)                 │
├─────────────────────────────────────┤
│ 成员变量 1                          │
├─────────────────────────────────────┤
│ 成员变量 2                          │
└─────────────────────────────────────┘

1.2 空基类优化(EBO)

空基类优化:

没有 EBO:
┌─────────────────────────────────────┐
│ 空基类(1 字节)                     │
├─────────────────────────────────────┤
│ 派生类成员                           │
└─────────────────────────────────────┘

有 EBO:
┌─────────────────────────────────────┐
│ 派生类成员(空基类不占空间)          │
└─────────────────────────────────────┘

二、GCC vs LLVM 差异对比

┌────────────────────────┬──────────────────────┬──────────────────────┐
│ 特性                    │ GCC (libstdc++)      │ LLVM (libc++)        │
├────────────────────────┼──────────────────────┼──────────────────────┤
│ vptr 位置              │ 对象起始地址         │ 对象起始地址         │
│ EBO                    │ 支持                 │ 支持                 │
│ packed 结构            │ __attribute__((packed))│ __attribute__((packed))│
│ aligned 结构           │ alignas              │ alignas              │
│ 最小大小               │ 1 字节               │ 1 字节               │
└────────────────────────┴──────────────────────┴──────────────────────┘

三、Itanium ABI

3.1 布局规则

Itanium ABI 布局规则:

1. 基类子对象按声明顺序排列
2. 虚基类放在最后
3. vptr 通常在对象起始地址
4. 对齐填充按最大成员对齐

四、最佳实践

对象模型使用指南:

1. 注意对象大小:
   · 使用 sizeof 检查
   · 避免不必要的填充

2. 使用 EBO:
   · 空基类不占空间
   · 适合 policy-based 设计

3. 注意对齐:
   · 使用 alignas 控制对齐
   · SIMD 数据需要对齐

4. 避免 UB:
   · 不要 reinterpret_cast 对象
   · 使用 std::launder 访问新对象

延伸阅读

基于 MIT 许可发布