Empty base optimization
允许空基类子对象的大小为零。
目录 |
说明
任何
对象
或成员子对象的大小必须至少为1,即使该类型是空的
类类型
(即没有非静态数据成员的类或结构体),
(除非使用
[[
no_unique_address
]]
,详见下文)
(C++20 起)
,这是为了确保同一类型的不同对象的地址始终不同。
然而,基类子对象不受此约束,可以被完全优化出对象布局:
struct Base {}; // 空类 struct Derived1 : Base { int i; }; int main() { // 任何空类类型对象的大小至少为1 static_assert(sizeof(Base) >= 1); // 空基类优化生效 static_assert(sizeof(Derived1) == sizeof(int)); }
当某个空基类同时也是第一个非静态数据成员的类型或其基类时,禁止进行空基类优化,因为在最终派生类型的对象表示中,要求同一类型的两个基类子对象必须具有不同地址。
这种情况的一个典型例子是 std::reverse_iterator 的简单实现(派生自空基类 std::iterator ),该实现将底层迭代器(同样派生自 std::iterator )作为其第一个非静态数据成员保存。
struct Base {}; // 空类 struct Derived1 : Base { int i; }; struct Derived2 : Base { Base c; // Base 类型成员,占1字节,后接为 i 准备的填充字节 int i; }; struct Derived3 : Base { Derived1 c; // 继承自 Base,占 sizeof(int) 字节 int i; }; int main() { // 空基类优化不适用: // 基类占1字节,Base 成员占1字节 // 后接2字节填充以满足 int 对齐要求 static_assert(sizeof(Derived2) == 2*sizeof(int)); // 空基类优化不适用: // 基类至少占1字节加上为满足首个成员 //(其对齐要求与 int 相同)对齐所需的填充字节 static_assert(sizeof(Derived3) == 3*sizeof(int)); }
|
对于
标准布局类型
,必须进行空基类优化,以确保将标准布局对象指针使用
|
(C++11 起) |
|
若空成员子对象使用属性
运行此代码
struct Empty {}; // empty class struct X { int i; [[no_unique_address]] Empty e; }; int main() { // the size of any object of empty class type is at least 1 static_assert(sizeof(Empty) >= 1); // empty member optimized out: static_assert(sizeof(X) == sizeof(int)); } |
(C++20 起) |
注释
空基类优化通常被分配器感知的标准库类(
std::vector
、
std::function
、
std::shared_ptr
等)所采用,以避免当其分配器为无状态时占用额外的存储空间。这是通过将所需数据成员之一(例如
vector
的
begin
、
end
或
capacity
指针)存储在与
boost::compressed_pair
等效的结构中并与分配器共同实现的。
在MSVC中,空基类优化并未完全符合标准要求( 为何空基类优化(EBO)在MSVC中无法生效? )。
参考文献
- C++23 标准 (ISO/IEC 14882:2024):
-
- 7.6.10 相等运算符 [expr.eq]
-
- 7.6.2.5 Sizeof 运算符 [expr.sizeof]
-
- 11 类 [class]
-
- 11.4 类成员 [class.mem]
- C++20 标准 (ISO/IEC 14882:2020):
-
- 7.6.10 相等运算符 [expr.eq]
-
- 7.6.2.4 Sizeof 运算符 [expr.sizeof]
-
- 11 类 [class]
-
- 11.4 类成员 [class.mem]
- C++17 标准 (ISO/IEC 14882:2017):
-
- 8.10 相等运算符 [expr.eq]
-
- 8.3.3 Sizeof 运算符 [expr.sizeof]
-
- 12 类 [class]
-
- 12.2 类成员 [class.mem]
- C++14 标准 (ISO/IEC 14882:2014):
-
- 5.10 相等运算符 [expr.eq]
-
- 5.3.3 Sizeof 运算符 [expr.sizeof]
-
- 9 类 [class]
-
- 9.2 类成员 [class.mem]
- C++11 标准 (ISO/IEC 14882:2011):
-
- 5.10 相等运算符 [expr.eq] (页: 2)
-
- 5.3.3 Sizeof 运算符 [expr.sizeof] (页: 2)
-
- 9 类 [class] (页: 4,7)
-
- 9.2 类成员 [class.mem] (页: 20)
- C++98 标准 (ISO/IEC 14882:1998):
-
- 5.10 相等运算符 [expr.eq] (页: 2)
-
- 5.3.3 Sizeof 运算符 [expr.sizeof] (页: 2)
-
- 9 类 [class] (页: 3)
外部链接
| More C++ Idioms/Empty Base Optimization — 维基教科书 |