No, objects do not persist this way.
C++ objects are defined primarily by their lifetime, which is scoped to the program.
So if you want to recycle an object from raw storage, there has to be a brand new object in program (2) with its own lifetime. reinterpret_cast
'ing memory does not create a new object, so that doesn't work.
Now, you might think that inplace-newing an object with a trivial constructor at that memory location could do the trick:
struct MyObj {
int x;
int y;
float z;
};
void foo(char* raw_data) {
// The content of raw_data must be treated as being ignored.
MyObj* obj = new (raw_data) MyObj();
}
But you can't do that either. The compiler is allowed to (and demonstrably does sometimes) assume that such a construction mangles up the memory. See C++ placement new after memset for more details, as well as a demonstration.
If you want to initialize an object from a given storage representation, you must use memcpy()
or an equivalent:
void foo(char* raw_data) {
MyObj obj;
static_assert(std::is_standard_layout_v<MyObj>);
std::memcpy(&obj, raw_data, sizeof(MyObj));
}
Addendum: It is possible to do the equivalent of the desired reinterpret_cast<>
by restomping the memory with its original content after creating the object (inspired by the IOC proposal).
#include <type_traits>
#include <cstring>
#include <memory>
template<typename T>
T* start_lifetime_as(void *p)
requires std::is_trivially_copyable_v<T> {
constexpr std::size_t size = sizeof(T);
constexpr std::size_t align = alignof(T);
auto aligned_p = std::assume_aligned<align>(p);
std::aligned_storage_t<size, align> tmp;
std::memcpy(&tmp, aligned_p, size);
T* t_ptr = new (aligned_p) T{};
std::memcpy(t_ptr , &tmp, size);
return std::launder<T>(t_ptr);
}
void foo(char* raw_data) {
MyObj* obj = start_lifetime_as<MyObj>(raw_data);
}
This should be well-defined in C++11 and up as long as that memory location only contains raw data and no prior object. Also, from cursory testing, it seems like compilers do a good job at optimizing that away.
see on godbolt