Consider a POSIX.1-2008 compliant operating system, and let fd be a valid file descriptor (to an open file, read mode, enough data...). The following code adheres to the C++
I believe simply casting does violate strict aliasing. Arguing that convincingly is above my paygrade, so here is an attempt at a workaround:
template<class T>
T* launder_raw_pod_at( void* ptr ) {
static_assert( std::is_pod<T>::value, "this only works with plain old data" );
char buff[sizeof(T)];
std::memcpy( buff, ptr, sizeof(T) );
T* r = ::new(ptr) T;
std::memcpy( ptr, buff, sizeof(T) );
return r;
}
I believe the above code has zero observable side effects on memory and returns a pointer to a legal T*
at location ptr
.
Check if your compiler optimizes the above code to a noop. To do so, it has to understand memcpy
at a really fundamental level, and constructing a T
has to do nothing to the memory there.
At least clang 4.0.0 can optimize this operation away.
What we do is we first copy the bytes away. Then we use placement new to create a T
there. Finally, we copy the bytes back.
We have a legally created T
with exactly the bytes we want in it.
But the copy away and back are to a local buffer, so it has no observable effect.
The construction of the object, if a pod, doesn't have to touch bytes either; technically the bytes are undefined. But compilers who are smart say "do nothing".
So the compiler can work out that all this manipulation can be skipped at runtime. At the same time, we have in the abstract machine properly created an object with the proper bytes at that location. (assuming it has valid alignment! But that isn't this code's problem.)