I am trying to determine what the strictly conforming pattern for using memory allocators with C++17 is. Specifically, moving away from the working in practice UB pattern:
example * foo = (example*)malloc(sizeof(example));
// no object here, don't use foo!
Therefore placement new into the allocated memory. Something like:
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <new>
struct example { // alignment <= max_align_t
example(int x) : x(x) {}
~example() {}
int x;
static void *operator new(size_t, example *p) { return p; }
};
int main() {
example *ex = nullptr;
{
void *m = malloc(sizeof(example));
if (!m) {
return 1;
}
ex = new (reinterpret_cast<example *>(m)) example(42);
// if one failed to store the result of the new expression, can retrieve it
// from m via launder
ex = std::launder(reinterpret_cast<example *>(m));
// now abandon all further instances of 'void *m'
}
// ... do some well defined things with the example object at *ex
All good, we have a properly constructed object. How do we free it?
// ...
{
ex->~example(); // lifetime has ended
// UB? We don't have a void* to pass to free
// free(ex);
// equivalent to above, it's still not a void*
// free(reinterpret_cast<void*>(ex));
// error, new defines: void launder(void*) = delete
// free(std::launder(reinterpret_cast<void*>(ex)));
// error: void pointer argument to __builtin_launder is not allowed
// free( __builtin_launder(reinterpret_cast<void*>(ex)));
// Quoting the rule book, 21.6.4 [ptr.launder]
// The program is ill-formed if T is a function type or cv void
// Out of options, guess it has to be free
free(ex);
}
}
void *
doesn't have the aliasing properties of a char*
. Can't even do arithmetic on void*.
'Free' is a difficult thing to search for. I can't see special case magic for free, but even if there is such, it won't help with platform_allocate/platform_deallocate pairs.
On the basis that launder definitely doesn't permit one to get the void* back, free(ex) in the above is presumably the right thing to do.
What makes free(ex) well defined?
Why is launder(void) forbidden? A pointer optimisation barrier applied at the end of the malloc() implementation seems a great idea.
What makes free(ex) well defined?
free
requires a pointer whose address is one directly returned by a call to malloc
. You have provided that. Why wouldn't it work?
Why is launder(void) forbidden?
Because it makes no sense. std::launder<T>
returns a pointer to an object of type T
within its lifetime whose address is the address of the given pointer. void
is an incomplete type; there cannot be objects of type void
. Therefore, std::launder<void>
cannot possibly function.
Memory allocation functions typically do not deal with pointers to objects. They deal in pointers to memory . The only thing they care about is whether the address of that pointer is one they can deal with.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.