I have a class whose purpose is to move data which might have alignment restrictions to or from a serialized memory buffer where the data is not aligned. I have set and get handlers as follows:
#include <cstring>
template<typename T>
struct handle_type {
static inline T get(const void *data) {
T value;
memcpy(&value, data, sizeof(T));
return value;
}
static inline void set(void *data, T value) {
memcpy(data, &value, sizeof(T));
}
};
After c++20 comes out, I am hoping it will become something like the following:
#include <bit>
template<typename T>
struct handle_type {
union unaligned { char bytes[sizeof(T)]; }; // EDIT: changed from struct
static inline T get(const void *data) {
return std::bit_cast<T>(*(const unaligned*)data);
}
static inline void set(void *data, T value) {
*(unaligned *)data = std::bit_cast<unaligned>(value);
}
};
Will it work? Or is the fact that I am using an inerim type, the unaligned struct type, liable to pose a problem?
Your
getfunction is UB unless the user has provided a pointer to anunalignedobject. Yoursetfunction is similarly UB unlessdatais anunalignedobject. Either of these cases violates strict aliasing. Remember: the strict aliasing back-door is about an actualchar*; that's not the same as an object that happens to contain achar*.Also,
setis potentially a compile error, depending entirely on whether or not the implementation ofunalignedis such that it has the same size asT. After all,unalignedmay have padding at the end.bit_castwants to deal primarily in objects, not random buffers of memory. For that, you should stick withmemcpy.That changes nothing; using a
uniondoesn't guarantee that the size of theunionis equal to the size of its largest data member. From [class.union]/2:Emphasis added: "sufficient", not "equal to". The standard permits implementations the ability to make the union larger than its largest data member, as such a size would still be "sufficient".