源代码显示new()在malloc返回的地址调用对象的构造函数

时间:2014-07-30 19:21:29

标签: c++ gcc new-operator

我设法找到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哪里可以找到这个?

2 个答案:

答案 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通过调用相应的构造函数/来构造第一次调用返回的内存中的对象 - 类初始化。