考虑以下代码:
#include <iostream>
#include <string>
union U
{
std::string s;
U()
{
new(&s) std::string;
}
void Set(std::string new_s)
{
s.~basic_string();
new(&s) std::string(std::move(new_s));
}
~U()
{
s.~basic_string();
}
};
int main()
{
U u;
u.Set("foo");
std::cout << u.s << '\n'; // Do I need `std::launder` here?
}
我知道,如果我使用字节数组而不是联合,我必须
std::launder(&s)
才能访问该字符串。但我这里需要它吗?
常识的答案似乎是“否”,但是标准在哪里祝福
union
不需要std::launder
?
u.s
只是定义为产生指向联合的 s
成员子对象的指针。 (即使 u.s
不在其生命周期内,即不处于活动状态,也是如此。)
所以不需要清洗。您已经拥有所需对象的左值。
即使您从指向联合对象的指针开始并尝试使用指针转换方法(更类似于字节数组方法),那么它仍然可以在没有
std::launder
的情况下工作,例如:
std::cout << *reinterpret_cast<std::string*>(&u) << '\n';
这是因为联合对象与每个 [basic.compound]/4.2 的任何成员子对象都是指针可相互转换的,这意味着
reinterpret_cast
将立即生成指向成员子对象的指针。