注:
- 了解operate new和operate delete各自的功能;
- 析构函数只是销毁对象,而不会释放掉内存,这也就解释了delete表达式为什么是执行了两步。
关于noexcept有关知识,请参考<http://blog.csdn.net/qianqin_2014/article/details/51321631>
定位new表达式
关于allocator的知识,请参考<http://blog.csdn.net/qianqin_2014/article/details/51323555>
定位new表达式的应用
1 经典示例:
-
#include <iostream>
-
#include <new>
-
const intchunk = 16;
-
class Foo
-
{
-
public :
-
int val( ) { return _val; }
-
Foo( ) { _val = 0; }
-
private :
-
int_val;
-
};
-
//预分配内存,但没有Foo对象
-
char*buf = new char[ sizeof(Foo) * chunk ];
-
int
-
main( void )
-
{
-
//在buf中创建一个Foo对象
-
Foo*pb = new (buf) Foo;
-
//检查一个对象是否被放在buf中
-
if ( pb->val() == 0 )
-
{
-
cout <<"new expressio worked!" <<endl;
-
}
-
//到这里不能再使用pb
-
delete[] buf;
-
return 0;
-
}
但我不了解这种“定位new表达式”相对于一般的new的优点是什么?它的用法比一般的new对象要复杂!
2使用定位new表达式作用
1)placement new的作用就是:创建对象但是不分配内存,而是在已有的内存块上面创建对象。用于需要反复 创建并删除的对象上,可以降低分配释放内存的性能消耗。
2)定位new表达式,允许程序员将对象创建在已经被分配好的内存中,new表的式的形式如下:
-
new (place_address) type
-
new (palce_address) type (initializer-list)
place_address必须是个指针,指向已经分配好的内存。为了使用这种形式的new表达式,必须包含头文件<new>。
定位new表达式不能调用delete删除 placement new的对象,需要人为的调用对象的析构函数,并且人为的释放掉占用的内存。
-
#include <iostream>
-
#include <new>
-
using namespace std;
-
const int chunk = 16;
-
class Foo
-
{
-
public:
-
int val(){return _val;}
-
Foo(){_val=0;}
-
private:
-
int _val;
-
};
-
int main()
-
{
-
// 预分配内存buf
-
char *buf = new char[sizeof(Foo) * chunk];
-
// 在buf中创建一个Foo对象
-
Foo *pb=new (buf) Foo;
-
// 检查一个对象是否被放在buf中
-
if(pb->val()==0) cout<<"new expression worked!"<<endl;
-
// 这里不存在与定位new表达式匹配的delete表达式,即:delete pb, 其实只是为了
-
// 释放内存的话,我们不需要这样的表达式,因为定位new表达式并不分配内存。
-
// 如果在析构函数中要做一些其他的操作呢?就要显示的调用析构函数。
-
// 当程序不再需要buf时,buf指向的内存被删除,它所包含的任何对象的生命期也就
-
// 都结束了。
-
delete[] buf;
-
return 0;
-
}
定位new表达式的应用:
在我们的程序中,首先使用malloc为对象分配空间,然后通过定位new表达式将对象创建在已经被分配好的内存中,完成构造函数的调用。
3)
“new (start) Screen;”
这是定位new操作
Screen *ps = new (start) Screen;
表示在已经开辟好的内存区start中为堆对象Screen申请一个内存
也就是说,如果start占100个字节,你现在从它的第1个字节开始,往里面写入Screen,这样做今后要释放内存的时候有麻烦,如果Screen里面有指针,并开辟了空间,那么delete ps会调用析构函 数,然而在释放指针变量所占的内存空间时也释放了为对象所分配的内存空间,所以start中的那块内存也丢失了,因为ps也指向了start.所以要避免这种情况,就要先ps->~Screen()这样显示的调用Screen的析构函数,再delete []start。