At least for GCC targeting x86_64, it is possible to investigate this question by looking at the assembly GCC generates for this simple program:
#include <iostream>
struct Foo
{
int x, y;
~Foo() { std::cout << "Delete foo " << this << std::endl; }
};
Foo * create()
{
return new Foo[8];
}
void destroy(Foo * p)
{
delete[] p;
}
int main()
{
destroy(create());
}
Using Compiler Explorer, we see this code generated for the create function:
create():
sub rsp, 8
mov edi, 72
call operator new[](unsigned long)
mov QWORD PTR [rax], 8
add rax, 8
add rsp, 8
ret
It looks to me like the compiler is calling operator new[] to allocate 72 bytes of memory, which is 8 bytes more than is needed for the storage of the objects (8 * 8 = 64). Then it is storing the object count (8) at the beginning of this allocation, and adding 8 bytes to the pointer before returning it, so the pointer points to the first object.
This is one of the methods what was listed in the document you linked to:
Over-allocate the array and put n just to the left of the first Fred object.
I searched a little bit in the source code of libstdc++ to see if this was implmented by the standard library or the compiler, and I think it's actually implemented by the compiler itself, though I could be wrong.