You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

《C++ Primer 5th》类内union首成员默认初始化相关疑问

问题核心解答

你遇到的差异本质是union首成员的类型特性和C标准中union初始化规则的适配问题,针对你提到的《C Primer 第五版》的描述和测试代码的差异,具体解释如下:

1. 先明确书上Token示例的特殊前提

Token类中的匿名union定义如下:

union { // 匿名union
    char   cval; // 首成员,基础平凡类型
    int    ival;
    double dval;
    std::string sval;
};

这个union的首成员cval是char类型,属于平凡类型:没有自定义构造函数、析构函数,不需要额外的资源管理。
C++标准中规定:如果union的首成员是平凡类型,且包含类的构造函数没有在初始化列表中显式初始化union的任意成员,那么union会执行默认初始化,本质就是给union分配对应大小的内存,首成员被初始化为不确定值的平凡类型,整个过程没有任何构造函数调用,也不会产生任何需要释放的资源。
书上所说的“拷贝构造函数中union的首成员被默认初始化”就是指这个场景:没有实际的构造操作,也没有需要销毁的资源,后续不管是给int、double成员赋值,还是用placement new构造string,都是完全安全的,不需要提前清理原有内容。

2. 你的测试代码和书里场景的本质差异

你定义的union首成员是自定义类型A,A有非平凡的默认构造函数和析构函数,这种情况下规则完全不同:

  • 如果union存在拥有非平凡构造函数的成员,那么union自身的默认构造函数会被隐式删除,除非你显式初始化union的某个成员。
  • 你自己定义的Foo拷贝构造函数没有在初始化列表中初始化union的任何成员,本质属于未定义行为,你观测到的“A构造函数只调用一次”只是未定义行为的一种表现,不代表通用规则。

3. 为什么Token的拷贝构造可以直接调用copyUnion

回到Token的场景,它的union首成员是平凡类型,默认初始化后没有需要清理的资源:

  • 如果拷贝的源Token持有的是int/char/double,直接给对应成员赋值即可,覆盖掉原来的不确定值,完全合法。
  • 如果拷贝的源Token持有的是string,直接用placement new在sval的地址构造新的string即可,原来的char类型成员是平凡类型,不需要调用析构函数,不会有资源泄漏。

内容的提问来源于stack exchange,提问作者Itachi Uchiwa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 00:30:01