【C/C++】EBO空基类优化介绍

空对象优化(Empty Base Optimization,简称 EBO)是 C++ 编译器的一种 优化技术,用于消除空类作为基类时占用的内存空间,从而避免浪费空间、提升结构体或类的存储效率。


1 什么是"空对象"?

一个**空类(empty class)**是指:

cpp 复制代码
class Empty {};

它没有任何数据成员(包括虚函数、虚继承等),仅有默认的构造/析构函数。根据 C++ 的标准:

每个对象都必须具有唯一的地址,即使它不包含任何数据。

所以如果你直接定义:

cpp 复制代码
Empty e1, e2;

编译器仍然会让 sizeof(Empty) >= 1,通常为 1 字节,以保证地址唯一性。


2 空对象优化(EBO)原理

空类作为基类时,如果派生类没有其它成员使用其地址,那么可以省略它占用的空间。

示例:空对象优化前后对比

cpp 复制代码
// 不继承空类:直接成员,浪费空间
class Empty {};

struct NotOptimized {
    int x;
    Empty e;
};

// 使用继承:可以应用 EBO
struct Optimized : Empty {
    int x;
};

对比 sizeof

cpp 复制代码
std::cout << sizeof(NotOptimized) << "\n";  // 可能是 8(int + 空类占1 + padding)
std::cout << sizeof(Optimized) << "\n";     // 通常是 4(只包含 int)

结果说明:

  • NotOptimized:包含一个 Empty 成员,因此占用额外空间;
  • OptimizedEmpty 作为基类,如果没有虚函数/虚继承,编译器可以完全消除其空间。

3 EBO 的典型应用场景

标准库容器优化

STL 中 std::functionstd::tuplestd::optional 等结构都大量使用了 EBO。

cpp 复制代码
template<typename T, typename Deleter = std::default_delete<T>>
class unique_ptr {
    T* ptr;
    Deleter deleter;  // 如果 Deleter 是空类,会占额外空间
};

如果不优化,unique_ptr<int, EmptyDeleter> 也会占两个指针大小(ptr + deleter),但 EBO 可以优化掉 deleter 空类的空间占用。


函数对象封装/策略模式

cpp 复制代码
template<typename F>
struct FuncWrapper : F {
    void operator()() { F::operator()(); }
};

如果 F 是空类,比如一个无状态 lambda 或策略类,EBO 可以让 FuncWrapper 大小为 1 或 0 字节。


4 EBO 的限制

有虚函数或虚继承

cpp 复制代码
struct Base {
    virtual void f() {}
};
  • 虚表指针会阻止 EBO。

多个相同空基类

cpp 复制代码
struct A {};
struct B1 : A {};
struct B2 : A {};  //  编译器不能合并两个 A 的地址

struct C : B1, B2 {};

C++ 要保证每个 A 的子对象地址不同,因此不能优化掉两个 A


5 C++20 的 [[no_unique_address]]

为了手动控制 EBO,C++20 引入了 [[no_unique_address]] 属性:

cpp 复制代码
template<typename T, typename Deleter>
struct SmartPtr {
    T* ptr;
    [[no_unique_address]] Deleter deleter;  // 允许优化
};
  • 即使 Deleter 是空类,编译器也不会强行分配空间;
  • 可应用于非基类成员(突破传统 EBO 只能作用于基类的限制);
  • 可读性和语义性更好。

总结

项目 是否允许空对象优化
空类作为成员 ❌ 不允许,至少占 1 字节
空类作为非虚基类 ✅ 可以优化掉空间
空类有虚函数/虚继承 ❌ 无法优化(有 vptr)
多继承多个相同空基类 ❌ 需保留唯一地址,不能优化
C++20 [[no_unique_address]] ✅ 可以显式允许成员优化
相关推荐
曦樂~9 分钟前
【Qt】信号与槽(Signal and Slot)- 简易计算器
开发语言·数据库·qt
歪歪10018 分钟前
React Native开发Android&IOS流程完整指南
android·开发语言·前端·react native·ios·前端框架
AA陈超25 分钟前
虚幻引擎5 GAS开发俯视角RPG游戏 P05-11 消息小部件
c++·游戏·ue5·游戏引擎·虚幻
yaoxin52112327 分钟前
212. Java 函数式编程风格 - Java 编程风格转换:命令式 vs 函数式(以循环为例)
java·开发语言
wangqiaowq27 分钟前
ImmutableList.of() 是 Google Guava 库 提供的一个静态工厂方法,用于创建一个不可变的(immutable)列表。
开发语言·windows·python
再卷也是菜37 分钟前
C++篇(14)二叉树进阶算法题
c++·算法
十五年专注C++开发42 分钟前
QDarkStyleSheet: 一个Qt应用的暗色主题解决方案
开发语言·c++·qt·qss
2401_8414956444 分钟前
【数据结构】最长的最短路径的求解
java·数据结构·c++·python·算法·最短路径·图搜索
麦麦鸡腿堡1 小时前
Java的代码块介绍与快速入门
java·开发语言
小龙报1 小时前
《算法每日一题(1)--- 连续因子》
c语言·开发语言·c++·windows·git·算法·visual studio