空基类优化

来自cppreference.com
< cpp‎ | language
 
 
C++ 语言
表达式
替代表示
字面量
布尔 - 整数 - 浮点
字符 - 字符串 - nullptr (C++11)
用户定义 (C++11)
工具设施
特性 (C++11)
类型
typedef 声明
类型别名声明 (C++11)
强制转换
隐式类型转换 - 显式类型转换
static_cast - dynamic_cast
const_cast - reinterpret_cast
内存分配
类特有的函数属性
特殊成员函数
模板
杂项
 

允许空的基类子对象大小为零。

[编辑] 解释

任何对象或成员子对象的大小要求至少为1,即使该类型是空的类类型(即一个无非静态数据成员的class或struct),为保证同一类型的不同对象地址始终有别。

然而,基类子对象不受这种制约,而且可以完全从对象布局中被优化掉:

#include <cassert>
 
struct Base {}; // 空类
 
struct Derived1 : Base {
    int i;
};
 
int main()
{
    // 任何空类类型的对象大小至少为1
    assert(sizeof(Base) == 1);
 
    // 应用空基优化
    assert(sizeof(Derived1) == sizeof(int));
}

若空基类之一亦为首个非静态数据成员的类型或其类型的基类,则空基优化被禁用,因为要求同类型二个基类子对象在最后导出类型的对象表示中拥有不同地址。

这种情况的典例是std::reverse_iterator的朴素实现(导出自空基类std::iterator),它保有底层迭代器(亦导出自std::iterator)为其首个非静态数据成员。

#include <cassert>
 
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对齐要求
    assert(sizeof(Derived2) == 2*sizeof(int));
 
    // 空基类优化不应用,
    // 基类占用至少1字节加填充以满足首个成员的对齐要求(其对齐要求同int)
    assert(sizeof(Derived3) == 3*sizeof(int));
}

对于标准布局类型StandardLayoutType要求有空基类优化,以维持指向标准布局对象的指针,用reinterpret_cast转换后,还指向其首成员,这是标准布局类型“无拥有非静态数据成员的基类,且无与其首个非静态数据成员同类型的基类”的原因。

(C++11 起)

[编辑] 注意

空基类优化常用于具备分配器的标准库类(std::vectorstd::functionstd::shared_ptr等),以避免为其分配器成员占用任何附加存储,若分配器为无状态。这由与分配器一同存储所要求数据成员之一(例如begin、end,或vector的capacity指针)于boost::compressed_pair的等价物来实现。


[编辑] 参考

  • C++11 standard (ISO/IEC 14882:2011):
  • 5.10 Equality operators [expr.eq](p: 2)
  • 5.3.3 Sizeof [expr.sizeof](p: 2)
  • 9 Classes [class](p: 4,7)
  • 9.2 Class members [class.mem](p: 20)
  • C++98 standard (ISO/IEC 14882:1998):
  • 5.10 Equality operators [expr.eq](p: 2)
  • 5.3.3 Sizeof [expr.sizeof](p: 2)
  • 9 Classes [class](p: 3)