前言
最近在看侯捷译的More Effective C++,看的过程有不少收获,发现自己对C++很多地方其实没有过多去了解,收获很多,记录一下。
三种new和delete
我们知道,new和delete都是C++里的关键字,同时也是操作符。new负责分配内存,delete释放内存。new和delete都有new operator、operator new,placement new,delete operator。下面分别介绍这几种操作
new operator和delete operator
new operator和delete operator就是我们经常使用的new和delete,这两个操作符是由语言内建的,就像sizeof操作符一样,不能被改变意义。当我们写出这样的代码时new operatorf和new delete在执行时分为两步:
1 2 |
string *ps=new string("new operator"); delete ps; |
- new operator 会先执行分配内存的操作,它会调用一个只分配内存的函数,这个函数就是operator new,它分配足够的内存,用来放置对象。new delete在释放内存前,会先调用对象的析构函数.
- 当new operator分配完内存的时候,它会调用一个构造函数,为刚才分配的内存中的对象设定初值。而delete operator调用完析构函数时,它会调用一个释放内存的函数 operator delete,这时候才会释放对象所占用的内存。
以上两行代码,拆分开来就是这样,先调用构造函数,分配内存,调用析构函数,释放内存,在编译器中的操作如下
1 2 3 |
void *memory=operator new(sizeof(string)); //取得原始内存 call string::string("Memory Management") on*memory;//将内存中的对象初始化 string *ps=static_cast<string*>(memory); |
- 注意new operator 和new delete都不可以被重载。
operator new和operator delete
上面一直说到new和delete其实在内部都会调用到这两个函数,这两个函数到底跟new和delete有什么区别呢?通常operator new ,operator delete声明如下:
1 2 |
void *ps=operator new(sizeof(string)); operator delete(ps); |
placement new(定位new)
写这篇文章,其实主要是写这个用法,还记得看到这个用法的时候,是在侯捷翻译的另一本书《STL 源码剖析》在讲空间配置器时看见的。
placement new是operator new的一种特殊版本,也是new operator的另一种用法,在已分配的内存上构造对象。要使用placement new必须要包含头文件new,#include或者#include<new.h>,调用示例就直接用书上的了。
1 2 3 4 5 6 7 8 9 |
class Widget { public: Widget(int widgetSize); }; Widget *constructWidgetInBuffer(void *buffer,int widgetSize) { return new(buffer) Widget(widgetSize); } |
此函数返回指针,指向一个Widget对象,它被构造于传递给此函数的一块内存缓冲区上。在函数内部唯一的表达式就是:
1
|
new (buffer) Widget(widgetSize);
|
于是,在buffer指向的这边空间,就构造了一个Widget对象。
注意,如果你使用了placement new,在某块内存中产生对象,应该避免对那块内存使用delete operator。因为这个delete operator会调用operator delete来释放内存,但是该内存内含的对象最初并非是由operator new分配得来的,毕竟placement new只是返回它所接受的指针而已,应该直接调用该对象的析构,然后在释放内存。
1 2 3 4 5 6 7 8 |
void *mallocShared(size_t size); void freeShared(void *memory); void *sharedMemory=mallocShared(sizeof(Widget)); Widget *pw=constructWidgeInBuffer(sharedMemory,10);//placement new用法 ... delete pw;//错。sharedMemory来自mallocShared,不是来自operator new pw.~Widget(); //可以,析构pw所指的Widget对象,但并未释放Widget占用的内存 freeShared(pw); //可以,释放pw所指的内存,不调用任何析构函数 |