I found this snippet
void* operator new(size_t nbytes)
{
if (nbytes == 0)
nbytes = 1; // so all alloc's get a distinct address
void* ans = malloc(nbytes + 4); // overallocate by 4 bytes
*(Pool**)ans = NULL; // use NULL in the global new
return (char*)ans + 4; // don't let users see the Pool*
}
here https://isocpp.org/wiki/faq/dtors
I spent over an hour now trying t understand what *(Pool**)ans = NULL;
does.
ans
is a void pointer, so I would assume it is cast to a Pool
pointer and the pool is set to 0. Not he pointer but the pool itself, because of the third *
on the left. But Pool has no operator=
defined.
pointer**
in a declaration is apparently a pointer to a pointer... but in this context this makes no sense to me, as ans
is a single pointer.
The only reason to use Pool**
here is semantic correctness, since presumably that "hidden" 4-byte header is supposed to be a pointer to a Pool
(so ans
is a pointer to a pointer to a Pool
, and *(Pool **)ans
has type Pool *
).
You couldn't do *(Pool *)ans = NULL
unless you were able to assign a Pool
to NULL
, and that is probably not the intended effect here anyways. Something like *(int **)ans = NULL
or the more ridiculous *(Pool ******)ans = NULL
would've had the same end effect but would have been semantically odd if it is ultimately intended to be a pointer to a Pool
.
At the end of the day you'll end up with:
+---+---+---+---+- - -
| 0 | 0 | 0 | 0 | ... and nbytes more bytes
+---+---+---+---+- - -
^ ans ^ returned address (ans + 4)
Where those first 4 bytes are intended to be a pointer to a Pool
somewhere.
Another way to think about this is to ignore the whole nbytes
thing, consider this general pattern:
void * ptr = malloc(sizeof(TYPE));
*(TYPE *)ptr = VALUE;
That should make sense. Now then if TYPE is a Pool *
and VALUE is NULL
and you fit it into that pattern, you can see how it all makes sense still:
void * ptr = malloc(sizeof(Pool *));
*(Pool **)ptr = NULL;
And then in your case you're still basically doing that although you're allocating some extra bytes at the end, but that's irrelevant to the types here.
As an aside, it's potentially asking for trouble here (and also semantically lazy) to hard-code 4
everywhere instead of sizeof(Pool *)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With