The constructor call is inserted at the site of the new-expression by the compiler. You can look at the disassembly of a simple program:
struct A { A() noexcept; ~A() = default; } ;
int main(){
new A;
}
produces for the new A;
expression (with g++ 4.9 at -O0
on Linux 64-bit):
movl $1, %edi ; copy the size of A into edi (the lower 32 bits of `rdi`)
call operator new(unsigned long) ; call the operator new function to allocate memory
movq %rax, %rdi ; copy the return value (in rax) to rdi
call A::A() ; call the constructor
x64 calling convention on Linux for a function taking a single integer or pointer parameter is that the parameter is passed in the rdi
register and the return value is placed in rax
. (While A::A()
seems to take no parameter, like all non-static class member functions, it has a hidden this
parameter.) So in this case, the compiler generates code to copy the pointer returned by operator new()
in rax
to rdi
, to be passed to A
's constructor as the hidden this
parameter, and then calls the constructor.
Note that this code is vastly simplified by declaring A::A()
as noexcept
, so the compiler can assume that the constructor call will never throw an exception.
As to placement new, it's implemented in the same way - except that it calls the placement operator new(size_t, void *)
- whose implementation simply returns the pointer passed. The compiler then generates code that calls the constructor, passing the return value of the placement operator new()
as the this
parameter.