Let's say I have an 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));
}
Is there any undefined behavior in the A::WriteVal method?
My guess would be NO for these reasons:
- Reinterpret casting between a uint64_t *andImpl *on it's own is ok since the alignment of the pointee types is the same.
- There is only UB if ptrwere to be dereferenced explicitely since that would break strict aliasing rules.
- memcpycan be safely used in substitution of explicit dereferencing regardless of the original type of the pointer.
Is my reasoning correct? If this is also considered UB, is there a nice C++ way of writing to an opaque type without illegal type punning methods.
My goal is to cleanly perform operations on an opaque value that, under the hood, represents a struct that users shouldn't know the details about.
 
    