为何C++中派生结构体大小会因基类成员是否初始化而不同?
基类成员默认初始化引发派生类大小差异的原因
先看问题中的代码:
#include <cstdint> struct B1 { int x; short y = 0; }; struct D1 : B1 { short z; }; struct B2 { int x; short y; }; struct D2 : B2 { short z; }; static_assert(sizeof(D1) == sizeof(D2));
在GCC 14.2和Clang 18.0.1中,这段代码编译失败,编译器提示断言条件sizeof(D1) == sizeof(D2)不成立,实际大小对比为8 == 12。
差异原因解析
这种现象的核心是C++标准对平凡可复制类型的布局规则,以及默认成员初始化器对类平凡性的影响:
类的平凡性判定
B2没有默认成员初始化器,所有成员都是基础类型,编译器生成的默认构造函数、析构函数、赋值运算符都是平凡的,因此B2属于平凡可复制类型。这类类型的内存布局必须严格连续,保证能通过memcpy等低级内存操作安全复制。B1中的short y = 0是默认成员初始化器,这会让编译器生成的默认构造函数变为非平凡(需要自动初始化y),因此B1不属于平凡可复制类型。
派生类布局的优化限制
- 针对平凡可复制的基类
B2:编译器不能将派生类D2的成员z放入B2的尾部填充空间。B2的布局是int x(4字节)+short y(2字节),为满足int的4字节对齐要求,尾部会填充2字节,总大小8字节。D2的z必须放在B2内存之后,占用2字节,之后再填充2字节以满足4字节对齐,最终D2总大小为12字节。 - 针对非平凡可复制的基类
B1:编译器不受平凡可复制类型的布局限制,可以做优化,将D1的成员z直接放入B1的尾部填充空间中。因此D1的总大小和B1一致,为8字节。
- 针对平凡可复制的基类
内容的提问来源于stack exchange,提问作者MarkB
相关产品推荐
相关产品推荐

