假设我有一个 API:
// api.h - Others can #include this header
#include <cstdint>
class A {
public:
// Write data into an opaque type.
// The user shouldn't directly access the underlying bits of this value.
// They should use this method instead.
void WriteVal(uint32_t data);
private:
uint64_t opaque_value_;
};
// api.cpp
#include <cstdlib>
#include "api.h"
namespace {
// This is the underlying struct that the opaque value represents.
struct alignas(8) Impl {
uint32_t x;
uint32_t y;
};
} // namespace
void A::WriteVal(uint32_t data) {
uint64_t *opaque_ptr = &opaque_value_;
Impl *ptr = reinterpret_cast<Impl *>(opaque_ptr);
memcpy(&ptr->y, &data, sizeof(data));
}
该方法中是否有任何未定义的行为A::WriteVal
?
由于以下原因,我的猜测是否定的:
- 重新解释 a
uint64_t *
和Impl *
它自己之间的转换是可以的,因为指针类型的对齐方式是相同的。 - 如果
ptr
要明确取消引用,则只有 UB,因为这会破坏严格的别名规则。 memcpy
无论指针的原始类型如何,都可以安全地用于替代显式取消引用。
我的推理正确吗?如果这也被认为是 UB,那么是否有一种很好的 C++ 方式来写入不透明类型而没有非法类型双关语方法。
我的目标是对一个不透明的值进行干净的操作,在底层,它代表一个用户不应该知道细节的结构。