为何[[no_unique_address]]在MSVC中会与基类产生冲突?
问题:[[no_unique_address]]在MSVC中与基类冲突导致结构体大小不符合预期?
以下程序在除MSVC外的所有编译器中返回1,而在MSVC中返回2:
struct E1 { }; struct E2 { }; struct #ifdef _MSC_VER __declspec(empty_bases) // This doesn't make any difference #endif S : E1 { char c; [[no_unique_address]] #ifdef _MSC_VER [[msvc::no_unique_address]] #endif E2 e; }; int main() { return sizeof(S); }
为何[[no_unique_address]]特性在MSVC中会与基类产生冲突,导致结构体S的大小不符合预期?按特性设计,它不应让成员e与c重叠吗?
回答
这是因为MSVC在处理空基类和带[[no_unique_address]]的空成员时,没有正确适配空基类优化(EBO)与空成员优化的组合规则。
按照C++标准,[[no_unique_address]]允许空类型的成员与其他非静态数据成员、基类子对象共享内存地址,只要它们的类型互不相同即可——这里E1和E2是不同的空类型,c是char类型,理论上E2成员e完全可以和c或基类E1的子对象重叠,让S的大小保持为1。
但MSVC的实现存在限制:当结构体同时包含非空数据成员(比如这里的char c)和空基类时,它不会将带[[no_unique_address]]的空成员与非空成员进行地址重叠。反而会为空成员e单独分配一个字节,最终导致sizeof(S)变成2。
你添加的__declspec(empty_bases)和[[msvc::no_unique_address]]没有效果,因为MSVC本身支持空基类优化,也能识别标准的[[no_unique_address]]特性,只是在这种“空基类+非空成员+带no_unique_address的空成员”的组合场景下,处理逻辑存在问题,和这些额外修饰无关。
内容的提问来源于stack exchange,提问作者user541686
相关产品推荐
相关产品推荐

