std::memmove() 从一个工会成员到另一个工会成员是否合法?

问题描述 投票:0回答:1
此代码尝试在不违反严格别名规则的情况下将内存内容重新解释为不同类型。 有人建议将其作为“

使用 std::memmove 解决严格别名问题?”的答案,并且在回答之前可能值得阅读那里的评论。 #include <cstring> #include <cstdint> #include <iomanip> #include <iostream> struct Parts { std::uint16_t v[2u]; }; static_assert(sizeof (Parts) == sizeof (std::uint32_t)); static_assert(alignof(Parts) <= alignof(std::uint32_t)); int main() { union { std::uint32_t u; Parts p; }; u = 0xdeadbeef; std::clog << std::hex << u << " ~> "; std::memmove(&p, &u, sizeof u); std::clog << p.v[0] << ", " << p.v[1] << '\n'; }

我不相信
std::memmove()
调用是合法的,因为

class.union.general.2

联合类型对象的非静态数据成员最多可以在任何时候处于活动状态 。 但我的信念似乎没有得到认同。 这合法吗? 标准的哪些部分允许/禁止这样做?

c++ language-lawyer unions memmove
1个回答
0
投票
定义为隐式启动隐式生命周期对象的生命周期。

因此,只要 
p

(及其所有子对象)都是隐式生命周期类型,就像它们在这里一样,就没有问题。该行为是明确定义的。

p

将在
memmove
之后成为活跃会员。
但是,实现此目的的更好方法是简单地使用
std::start_lifetime_as

,这保证实际上不需要对内存位置进行任何访问。

另请注意,您不需要工会。在与上述完全相同的条件下,您可以简单地从 
memmove

到自身,然后

uint32_t

 + 
reinterpret_cast
 将原始指针指向 
std::launder
。当然,就像联合的情况一样,之后你就不能再使用原来的 
Parts
 对象了。
	
© www.soinside.com 2019 - 2024. All rights reserved.