如果我有一个包含非平凡类型数组的联合(例如
std::string
)
using namespace std;
struct MyUnion {
union {
char c;
string s[5];
};
MyUnion() {}
~MyUnion() {}
};
仅初始化该数组的一部分并使用它是否合法(根据 C++ 标准)?
MyUnion mu;
// construct 2 strings using placement new
new (&mu.s[0]) string();
new (&mu.s[1]) string();
// do something with the strings
do_something(mu.s[0]);
do_something(mu.s[1]);
// destruct 2 strings
mu.s[0].~string();
mu.s[1].~string();
由于某种原因,这个问题已被标记为重复,但这个问题具体是关于 arrays 并且仅初始化数组的一部分。提议的重复项不能回答这个问题。
仅初始化该数组的一部分并使用它是否合法(根据 C++ 标准)?
是的,但有一些麻烦。
MyUnion mu;
new (&mu.s[1]) string(); // #1
指针运算仅在数组对象上合法,并且#1处没有数组对象。因此,
mu.s[1]
本身就是未定义的行为。
在 C++20 之前,如果不启动所有
mu.s
子对象的生命周期,就无法启动数组 string
的生命周期。
使用 C++20,我们可以做到
MyUnion mu;
new (&mu.s) char[sizeof(mu.s)]; // #2
new (&mu.s[1]) string();
创建
char
数组是指定隐式创建对象的一项操作。 #2 之后,隐式创建了一个 string
数组,从而使 mu.s[1]
合法。
使用 C++23,首选解决方案是
MyUnion mu;
std::start_lifetime_as<decltype(MyUnion::s)>(&mu.s);
new (&mu.s[1]) string();