C++标准下,联合中非平凡类型数组仅初始化部分是否合法?
问题:C++联合内非平凡类型数组的部分元素初始化是否合法?
定义包含std::string数组的联合代码如下:
using namespace std; struct MyUnion { union { char c; string s[5]; }; MyUnion() {} ~MyUnion() {} };
随后通过placement new仅初始化数组的前2个元素并使用的代码:
MyUnion mu; // 用placement new构造2个string new (&mu.s[0]) string(); new (&mu.s[1]) string(); // 使用这两个string do_something(mu.s[0]); do_something(mu.s[1]); // 析构这两个string mu.s[0].~string(); mu.s[1].~string();
请问按照C++标准,这种仅初始化数组部分元素并使用的操作是否合法?(注:此问题曾被误标为重复,本问题聚焦数组的部分初始化场景,现有重复问题未覆盖该内容。)
回答
这种操作是合法的,依据C++标准的核心规则如下:
联合活跃成员的切换规则
联合的活跃成员可通过显式构造新对象切换。当你用placement new构造mu.s[0]和mu.s[1]时,联合的活跃成员从默认的char c切换为数组s中被构造的元素对应的存储区域,这完全符合C++标准对联合成员激活的要求。数组元素的独立生命周期管理
数组的每个元素都是独立对象。对于非平凡类型数组,标准允许按需单独构造部分元素,只要确保:- 被构造的元素都被正确析构
- 未构造的元素绝不被访问
未构造的元素不存在合法生命周期,访问会触发未定义行为,但只使用已构造的元素完全合规。
非平凡类型在联合中的手动管理要求
由于MyUnion的默认构造/析构函数无法自动处理std::string这类非平凡类型的生命周期,你通过placement new手动构造、显式调用析构函数的方式,完全契合C++标准的规定——这类场景下,程序员必须手动负责非平凡成员的构造与析构逻辑。
需要额外注意:
- 绝对不能访问
mu.s[2]到mu.s[4]这些未构造的元素 - 必须保证每个被构造的
std::string都被显式析构,避免内存泄漏
内容的提问来源于stack exchange,提问作者eyelash
相关产品推荐
相关产品推荐

