我设法找到GCC源代码,显示new()运算符在new_op.cc中调用malloc():
_GLIBCXX_WEAK_DEFINITION void *
operator new (std::size_t sz) _GLIBCXX_THROW (std::bad_alloc)
{
void *p;
/* malloc (0) is unpredictable; avoid it. */
if (sz == 0)
sz = 1;
p = (void *) malloc (sz);
while (p == 0)
{
new_handler handler = __new_handler;
if (! handler)
_GLIBCXX_THROW_OR_ABORT(bad_alloc());
handler ();
p = (void *) malloc (sz);
}
return p;
}
但是,我试图找到从上面返回的内存地址调用对象构造函数的代码(我假设将使用placement new ??)。
我在GCC哪里可以找到这个?
答案 0 :(得分:4)
构造函数调用由编译器插入new-expression的站点。你可以看一下简单程序的反汇编:
struct A { A() noexcept; ~A() = default; } ;
int main(){
new A;
}
produces表示new A;
表达式(在Linux 64位上的-O0
处使用g ++ 4.9):
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
对于采用单个整数或指针参数的函数,Linux上的x64调用约定是参数在rdi
寄存器中传递,返回值放在rax
中。 (虽然A::A()
似乎没有参数,就像所有非静态类成员函数一样,它有一个隐藏的this
参数。)所以在这种情况下,编译器生成代码来复制{返回的指针在operator new()
到rax
中的{1}},作为隐藏的rdi
参数传递给A
的构造函数,然后调用构造函数。
请注意,通过将this
声明为A::A()
来大大简化此代码,因此编译器可以假定构造函数调用永远不会抛出异常。
关于placement new,它以相同的方式实现 - 除了它调用placement noexcept
- 其实现只返回传递的指针。然后,编译器生成调用构造函数的代码,将展示位置operator new(size_t, void *)
的返回值作为operator new()
参数传递。
答案 1 :(得分:2)
operator new
只是一个普通的旧函数,它只分配大容量内存,它不调用构造函数等。它是new
关键字的工作(有时称为new operator
,超级混乱)做后者。
参见Difference between 'new operator' and 'operator new'? 对于类似的问题。
所以当你打电话
Foo* foo = new Foo();
你实际上首先调用operator new(sizeof(Foo))
,它返回一个指向它分配的内存区域的指针,然后new
通过调用相应的构造函数/来构造第一次调用返回的内存中的对象 - 类初始化。