'malloc'和'new'如何运作?它们有何不同(实施明智)?

Joe*_*oel 8 c c++

我知道它们在语法上是如何不同的,并且C++使用new,而C使用malloc.但他们如何运作,在一个高级别的解释?

看看new/delete和malloc/free有什么区别?

Joh*_*itb 9

我只想指导你这个答案:new/delete和malloc/free有什么区别?.马丁提供了很好的概述.快速了解它们的工作原理(不必深入了解如何将它们作为成员函数重载):

新表达和分配

  1. 该代码包含一个提供type-id的new-expression.
  2. 编译器将查看类型是否使用分配函数重载operator new.
  3. 如果它找到运算符新分配函数的重载,则使用赋予new和sizeof(TypeId)作为其第一个参数的参数调用该函数:

样品:

new (a, b, c) TypeId;

// the function called by the compiler has to have the following signature:
operator new(std::size_t size, TypeOfA a, TypeOfB b, TypeOf C c);
Run Code Online (Sandbox Code Playgroud)
  1. 如果operator new无法分配存储,它可以调用new_handler,并希望它可以实现.如果仍然没有足够的地方,新的必须抛出std::bad_alloc或衍生出来.一个具有throw()(无抛出保证)的分配器,在这种情况下它应该返回一个空指针.
  2. C++运行时环境将创建由分配函数返回的内存中由type-id指定的类型的对象.

给出了一些特殊名称的特殊分配函数:

  • no-throw新.这需要nothrow_t作为第二个论点.如下所示的形式的新表达式将调用仅使用std :: size_t和nothrow_t的分配函数:

例:

new (std::nothrow) TypeId;
Run Code Online (Sandbox Code Playgroud)
  • placement new.这将void*指针作为第一个参数,而不是返回新分配的内存地址,它返回该参数.它用于在给定地址创建对象.标准容器使用它来预分配空间,但稍后只在需要时创建对象.

码:

// the following function is defined implicitly in the standard library
void * operator(std::size_t size, void * ptr) throw() {
    return ptr;
}
Run Code Online (Sandbox Code Playgroud)

如果分配函数返回存储,并且运行时创建的对象的构造函数抛出,则会自动调用operator delete.如果使用了一种新的形式,它需要额外的参数,比如

new (a, b, c) TypeId;
Run Code Online (Sandbox Code Playgroud)

然后调用带有那些参数的运算符delete.只有在删除完成时才调用该运算符删除版本,因为对象的构造函数确实抛出了.如果你自己调用delete,那么编译器将使用普通的operator delete函数只取一个void*指针:

int * a = new int;
=> void * operator new(std::size_t size) throw(std::bad_alloc);
delete a;
=> void operator delete(void * ptr) throw();

TypeWhosCtorThrows * a = new ("argument") TypeWhosCtorThrows;
=> void * operator new(std::size_t size, char const* arg1) throw(std::bad_alloc);
=> void operator delete(void * ptr, char const* arg1) throw();

TypeWhosCtorDoesntThrow * a = new ("argument") TypeWhosCtorDoesntThrow;
=> void * operator new(std::size_t size, char const* arg1) throw(std::bad_alloc);
delete a;
=> void operator delete(void * ptr) throw();
Run Code Online (Sandbox Code Playgroud)

new-expression和数组

如果你这样做

new (possible_arguments) TypeId[N];
Run Code Online (Sandbox Code Playgroud)

编译器使用的是operator new[]函数而不是plain operator new.操作符可以不完全传递第一个参数sizeof(TypeId)*N:编译器可以添加一些空间来存储创建的对象数(为了能够调用析构函数而需要).标准就是这样说的:

  • new T[5]导致操作员调用new[](sizeof(T)*5+x),并且
  • new(2,f) T[5]导致操作员的呼叫new[](sizeof(T)*5+y,2,f).