申请内存
申请内存的操作最后都要落在malloc上
通常情况下,operator new会调用malloc函数进行分配。
关于new和delete,通过new调用对象总是先分配内存,再调用构造函数,delete相反。new分配的空间在堆区,需要delete显式释放
new和delete
new,delete与构造和析构函数的调用顺序
可以看见调用new时先分配内存,再调用构造函数。而调用delete时先调用析构函数,再释放内存。在动态分配的内存中,上下各有两个cookie各占4个字节,且分配的内存16字节对齐,若不满16字节的用padding补齐
当调用new和delete时编译器会发生一下转化
调用new[ ] 和 delete[ ]时
过程大概为先调用operator new函数分配内存,然后将指向该内存的指针进行静态转型为该类指针,再调用该类的构造函数。
调用new[ ]时要分配4+N*size个字节,由于开始的指针占4个字节
可以用 Foo *p = new Foo(7);
的方式调用全局的new,也可以用::delete p;
调用全局delete
重载operator new()
重载时第一个参数必须为size_t,且后面参数列唯一,后面的参数列为place arguments,调用时以new(...)
输入place arguments。
重载operator delete()
只有当new所调用的ctor抛出异常时,才会调用重载版的operator delete(),用来归还未能创建成功的对象占用的内存。
在这个例子中在定义构造函数中抛出一个异常,下面是调用的方式:
通过调用Foo(1)
来抛出构造时异常,并让重载的第三个delete函数去释放构造对象失败占用的内存。(G4.9版本没有调用operator delete(void*, long)但G2.9版本调用了)
标准库中的例子
allocate
在VC6,BC5中的allocator都是以operator::new和operator::delete完成allocate()和delete()
GC2.9设计的标准库中allocator也有这样的实现,但默认调用的分配器不是allocator,而是alloc。其设计如下
大致是定义不同的链表,链表分别存8bytes,16bytes…,256bytes字节的内存块,用完后在malloc一个新的内存块,省下了很多相同的cookie的开销。
但在GCC4.9的容器默认使用的变成了allocator,它的allocate()和deallocate()都是简单地调用了operator new()和operator delete(),并没有进行任何特殊处理。GCC2.9中的alloc变成了pool_alloc,除pool_alloc之外还有很多其他类型的分配器,都在ext文件夹中。要使用时用vector<string, _gnu_cxx::_pool_alloc<string>>
使用该分配器