c++内存分配接口
很久之前的博客中我们谈到过c++中,new和delete的调用路径。但今天的介绍是更进一步的,希望读者可以了解到:我们自己也可以”重载“new、delete关键字的行为,为自定义的类设计独特的分配内存策略。
首先,需要回顾一下c++内存分配的接口。
图1 c++内存分配调用关系
可以这样理解:当你设计一个类时,如果类中有重载operator new,编译器会优先调用你设计的operator new分配内存;如果类内没有重载operator new,则调用全局的operator new。
当然,你也可以重载全局的::operator new,但这样就会影响到所有命名空间下new的使用了。这。。。杀伤力有点大,所以一般不会重载全局operator new。
delete和new类似(注意析构函数和释放内存的顺序相反),就不多说了。下面介绍两种常用的内存分配用法:
1. A::operator new(重载类内operator new)
重载类内operator new的效果已经很清楚了,可以避免分配该类实例内存时直接调用全局operator new,从而可以在其中加上一些自己想要的分配逻辑。
那么,到底啥时候需要自己设计一个类的分配内存逻辑呢——当一个类需要频繁地创造、销毁实例时,产生内存碎片的同时也会带来一点时间上的性能损耗。所以,这就需要对象池来统一管理这个类的内存。stl的alloc/allocator就实现了高效的对象池,几乎所有标准库容器的内存管理都是这样管理的。
operator delete也是如此,要和对象池的操作配套的。
2. placement new
placement new和上面就不太一样了。。并没有对应的“placement delete”,placement new并不分配内存,而只是把对象“放置”(构造)到已分配好的内存上。比如:
char* buf=new char[sizeof(A)];
A* a=new(buf) A();//只是调用了A的ctor,并没有分配内存
但你会发现这和现代c++的建议不符:实例的初始化尽量在一处完成。所以现代c++不太建议这样做,碰到这种写法知道是咋回事就行啦!毕竟可能还有历史遗留问题或者必须要这么用的极端情况呢。
|