gcc/clang与MSVC2015多继承空类时的内存填充规则差异解析
多继承空类的大小差异:C++标准依据解析
先把你的测试代码格式化一下,方便看:
#include <cstdint> using namespace std; class Empty1 {}; static_assert(sizeof(Empty1) == 1, "Expected size of 1 for Empty1"); class Empty2 {}; static_assert(sizeof(Empty2) == 1, "Expected size of 1 for Empty2"); class Empty3 : Empty2, Empty1 {}; static_assert(sizeof(Empty3) == 1, "Expected size of 1 for Empty3");
你碰到的GCC/Clang和MSVC2015的行为差异,核心原因是空基类优化(Empty Base Class Optimization, EBCO)的实现策略不同,而C++标准明确允许这种差异存在。
标准条款依据
在C标准的**[class.size]**章节(不同版本编号略有调整:C11为9.2.15,C++17及之后是10.3.2)里,有明确规定:
类的大小不得小于1字节。如果一个类是空的(无静态数据成员、无虚函数、无虚基类),那么当它作为基类时,实现可以选择不为其分配额外存储空间——只要不会和其他基类或成员的存储空间重叠即可。
划个重点:这是可选优化,不是强制要求。标准只规定了空类本身的大小至少为1,但空基类是否要占存储空间,完全由编译器自行决定。
为什么不同编译器表现不同
- GCC和Clang做了更激进的EBCO:哪怕多继承多个空基类,它们也会把这些空基类的存储空间合并,只保留1字节的最小大小,所以
sizeof(Empty3)是1。 - MSVC2015的EBCO实现比较保守:在多继承多个空基类的场景下,它没有合并存储空间,每个空基类都占1字节,所以
sizeof(Empty3)会是2,导致你的static_assert触发失败。
补充一句:MSVC后续版本(比如2017及之后)已经改进了EBCO的实现,多继承空基类时也能做到大小为1,但2015版本的行为确实符合标准的允许范围。
内容的提问来源于stack exchange,提问作者GaspardP
相关产品推荐
相关产品推荐

