Допустим, у меня есть 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
?
Моё предположение было бы НЕТ по следующим причинам:
- Переинтерпретировать приведение между
uint64_t *
и Impl *
само по себе нормально, поскольку выравнивание типов pointee одинаково. - Существует только UB, если
ptr
были быть явно разыменованным, поскольку это нарушило бы строгие правила наложения имен. memcpy
можно безопасно использовать вместо явной разыменования независимо от исходного типа указателя.
Является ли мой рассуждения верны? Если это также считается UB, есть ли хороший способ записи в C ++ непрозрачного типа без недопустимых методов штамповки типов.
Моя цель состоит в том, чтобы аккуратно выполнить операции над непрозрачным значением, которое под капотом представляет структура, о которой пользователи не должны знать детали.