空基类优化
允许空基类子对象的尺寸为零。
内容 |
[编辑] 解释
任何 对象 或成员子对象的尺寸都必须至少为 1,即使该类型为空 类类型(即,没有非静态数据成员的类或结构体),(除非使用 [[no_unique_address]]
,见下文)(自 C++20 起) 为了能够保证相同类型不同对象的地址始终不同。
但是,基类子对象不受此约束,可以完全从对象布局中优化掉。
struct Base {}; // empty class struct Derived1 : Base { int i; }; int main() { // the size of any object of empty class type is at least 1 static_assert(sizeof(Base) >= 1); // empty base optimization applies static_assert(sizeof(Derived1) == sizeof(int)); }
如果空基类也是类型或第一个非静态数据成员类型的类型或基类,则禁止空基类优化,因为要求相同类型的两个基类子对象在最派生类型的对象表示中具有不同的地址。
这种情况的典型例子是 std::reverse_iterator(从空基类 std::iterator 派生)的朴素实现,它保存底层迭代器(也从 std::iterator 派生)作为其第一个非静态数据成员。
struct Base {}; // empty class struct Derived1 : Base { int i; }; struct Derived2 : Base { Base c; // Base, occupies 1 byte, followed by padding for i int i; }; struct Derived3 : Base { Derived1 c; // derived from Base, occupies sizeof(int) bytes int i; }; int main() { // empty base optimization does not apply, // base occupies 1 byte, Base member occupies 1 byte // followed by 2 bytes of padding to satisfy int alignment requirements static_assert(sizeof(Derived2) == 2*sizeof(int)); // empty base optimization does not apply, // base takes up at least 1 byte plus the padding // to satisfy alignment requirement of the first member (whose // alignment is the same as int) static_assert(sizeof(Derived3) == 3*sizeof(int)); }
如果发生多重继承,则具体的优化是特定于编译器的。在 MSVC 中,空基类优化仅在最后一个空基类上应用,其余的空基类不应用空基类优化,并且分配一个字节。在 GCC 中,无论存在多少个空基类,空基类都会应用空基类优化,不分配任何空间,空基类的地址与派生类对象的第一个地址相同。
空基类优化对于 StandardLayoutTypes 是必需的,以保持通过 |
(自 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
的分配器中实现的。
[编辑] 参考资料
- 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] (p: 2)
- 5.3.3 sizeof [expr.sizeof] (p: 2)
- 9 类 [class] (p: 4,7)
- 9.2 类成员 [class.mem] (p: 20)
- C++98 标准 (ISO/IEC 14882:1998)
- 5.10 等号运算符 [expr.eq] (p: 2)
- 5.3.3 sizeof [expr.sizeof] (p: 2)
- 9 类 [class] (p: 3)
[编辑] 外部链接
更多 C++ 惯用法/空基优化 — 维基教科书 |