是否可以使用联合成员作为对象存储?
Is it possible to use a union member as object storage?
我想知道我们是否可以使用一个union
成员作为显式初始化和析构对象的存储,例如在下面的代码中:
struct X
{
X() { std::cout << "C"; }
~X() { std::cout << "D"; }
};
struct X_owner
{
union
{
X x; // storage for owned object
};
X_owner()
{
new (&x) X{};
}
~X_owner()
{
(&x)->~X();
}
};
int main()
{
X_owner xo;
}
打印输出仅符合预期 CD
。现场演示:https://godbolt.org/z/M1Gov4o4d
这个问题是由一项编程作业引发的,在该作业中,学生应该明确定义对象的存储。预期的解决方案是 unsigned char
或 std::byte
或 std::aligned_storege
类型的适当对齐和大小的缓冲区。然而,他们中很少有人在他们的解决方案中使用这种方式 union
。我不确定这是否正确,尽管我找不到任何错误。
注意:为了简单起见,我在这个例子中不关心copy/move语义。
显示的代码是正确的。为了功能完整,应该正式定义复制构造函数和赋值运算符。如果 union
要容纳另一个对象,事情会很快变得复杂。为了保持有效,包装器对象将需要明确跟踪联合中构建的底层对象,并自行处理这些问题。
但是,如果事情朝那个方向发展,你可以让 std::variant
处理它。
确实有效
[class.base.init]
9 In a non-delegating constructor, if a given potentially constructed subobject is not designated by a mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has no ctor-initializer), then
- [...]
- otherwise, if the entity is an anonymous union or a variant member ([class.union.anon]), no initialization is performed;
- [...]
所以 x
没有被初始化,所以在它的生命周期内没有被初始化,直到一个人明确地对那块存储做一些事情来在那里创建一个对象。新的放置甚至没有替换该存储中的对象,直到 new 表达式才出现。所以我们甚至没有深入研究可能需要 std::launder
的地方。
似乎是一种可以接受的方法。
我想知道我们是否可以使用一个union
成员作为显式初始化和析构对象的存储,例如在下面的代码中:
struct X
{
X() { std::cout << "C"; }
~X() { std::cout << "D"; }
};
struct X_owner
{
union
{
X x; // storage for owned object
};
X_owner()
{
new (&x) X{};
}
~X_owner()
{
(&x)->~X();
}
};
int main()
{
X_owner xo;
}
打印输出仅符合预期 CD
。现场演示:https://godbolt.org/z/M1Gov4o4d
这个问题是由一项编程作业引发的,在该作业中,学生应该明确定义对象的存储。预期的解决方案是 unsigned char
或 std::byte
或 std::aligned_storege
类型的适当对齐和大小的缓冲区。然而,他们中很少有人在他们的解决方案中使用这种方式 union
。我不确定这是否正确,尽管我找不到任何错误。
注意:为了简单起见,我在这个例子中不关心copy/move语义。
显示的代码是正确的。为了功能完整,应该正式定义复制构造函数和赋值运算符。如果 union
要容纳另一个对象,事情会很快变得复杂。为了保持有效,包装器对象将需要明确跟踪联合中构建的底层对象,并自行处理这些问题。
但是,如果事情朝那个方向发展,你可以让 std::variant
处理它。
确实有效
[class.base.init]
9 In a non-delegating constructor, if a given potentially constructed subobject is not designated by a mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has no ctor-initializer), then
- [...]
- otherwise, if the entity is an anonymous union or a variant member ([class.union.anon]), no initialization is performed;
- [...]
所以 x
没有被初始化,所以在它的生命周期内没有被初始化,直到一个人明确地对那块存储做一些事情来在那里创建一个对象。新的放置甚至没有替换该存储中的对象,直到 new 表达式才出现。所以我们甚至没有深入研究可能需要 std::launder
的地方。
似乎是一种可以接受的方法。