包含带非平凡默认构造函数的glm::vec2的union引发构造报错
问题根因
- 你的
Foo结构体默认构造函数被隐式删除,核心原因是内部匿名联合体包含了非平凡默认构造的类型glm::vec2:C++标准规定,当联合体中存在没有用户提供默认构造函数的非平凡类型成员时,整个联合体的默认构造函数会被隐式删除,外层结构体Foo的默认构造函数因为依赖联合体的构造,也会跟着被删除。
解决方案1:显式指定联合体的激活成员(不需要placement new,最常用)
直接在Foo的构造函数里主动初始化你需要的联合体成员即可,比如你要默认用size的话,改写成:
struct Foo { union { glm::vec2 size; struct { float width, height; }; }; // 显式初始化联合体的size成员,让构造函数合法 Foo() : size(0.0f, 0.0f) {} };
如果默认要激活的是width/height那个匿名结构体,就写成:
Foo() : width(0.0f), height(0.0f) {}
改完之后直接用new Foo就不会报错了。
解决方案2:使用placement new的实现方式
如果你确实有场景需要先分配内存、再晚一点初始化联合体成员,就可以用placement new,步骤如下:
- 先分配足够容纳
Foo的裸内存,不调用构造函数 - 用placement new在已分配的内存上构造你需要激活的联合体成员
示例代码:
struct Foo { union { glm::vec2 size; struct { float width, height; }; }; Foo() = default; }; // 分配裸内存,大小和对齐要求匹配Foo void* buf = operator new(sizeof(Foo)); Foo* foo = static_cast<Foo*>(buf); // 用placement new显式构造glm::vec2成员,激活size分支 new (&foo->size) glm::vec2(1.0f, 2.0f); // 使用完之后手动析构激活的成员,再释放内存 foo->size.~vec2(); operator delete(buf);
注意:用placement new的场景下,你必须自己手动管理联合体的激活状态、析构对应的成员,不能直接调用
delete foo,否则会出现未定义行为。
内容的提问来源于stack exchange,提问作者Ariel Malka
相关产品推荐
相关产品推荐

