new的三种使用方法
我们通常情况下使用new都是普通的new,并不会接触其他的两种类型,那么今天我就带你们了解一下不同的new,并且在了解这两种之后可以帮助我们更好的进行内存空间的开辟。
- plain new/delete
这是普通的new,也就是我们常使用的new,先来看它的函数原型吧。
void *operator new(std::size_t)throw(std::bad_alloc);
void operator delete(void*)throw();
从函数原型我们可以看出来,new是已经经过运算符重载的,它执行失败后会抛出一个异常,所以我们如果通过判断返回值是不是NULL来决定是否开辟空间失败,那一定是徒劳的。
plain new 的一种使用方法
char* Getmemory(unsigned long size)
{
char *p = new char[size];
return p;
}
void main()
{
char *p = Getmemory(1000000);//可能抛出std::bad_alloc异常
delete []p;
}
catch(const std::bad_alloc& ex){
cout<<ex.what()<<endl;
}
}
这段代码就是使用C++常见的异常处理,如果开辟内存失败,就会抛出一个异常,然后会被相应的catch捕获,理解起来应该不是太难。
nothrow new/delete
从字面意思我们就知道这肯定是不抛出异常的new,这种new的使用在失败时会返回NULL,所以它不需要设置异常处理器,通过返回值就可以判断啦,看下它的函数原型吧。
void* operator new(std::size_t,const std::nothrow_t&)throw();
void operator delete(void*)throw();
nothrow new/delete的使用方法如下
void func(unsigned long length)
{
unsigned char* p = new(nothrow)unsigned char[length];
if(p == NULL) cout<<"allocate failed"<<endl;
delete []p;
}
这种new的方式也很好理解,只需要通过返回值就可以判断是否开辟空间成功
placement new/delete
这种形式的new允许在一块已经分配成功的内存上重新构造对象或者对象数组。placement new不用担心内存分配失败,因为它根本不会开辟内存,它做的一件事就是调用对象的构造函数。且看它的函数原型
void* _operator new(size_t ,void*);
void _operator delete(void*,void*);
placement new 的语法?
typename *q = new(p)type-name;
p是已经分配成功的内存区的首地址,它被转换为目标类型的指针q,因此p和q相等
placement new 的使用方法?看下面啦
void main()
{
using namespace std;
char *p = new(nothrow)char[4];
if(p == NULL) {
cout<<"allocate failed"<<endl;
exit(-1);
}
long *q = new(p)long(1000);
....
delete []p;
}
placement new的主要用途?
- 反复使用一块较大的动态分配成功的内存来构造不同类型的对象或者他们的数组
- 使用placement new 构造起来的对象或者数组,要显式地调用它们的析构函数来销毁(析构函数并不释放对象的内存),千万不要使用delete。因为placement new 构造起来的对象或者数组的大小并不一定等于原来分配的内存大小,因此使用delete会造成内存泄漏,或者在之后释放内存时出现运行时错误。
void main()
{
using namespace std;
char *p = new(nothrow)char[sizeof(ADT)+2];
if(p == NULL) {
cout<<"allocate failed"<<endl;
exit(-1);
}
ADT *q = new(p)ADT;
...
delete q; //在这里调用肯定出错
q->ADT::~ADT();//显式调用析构函数
delete []p; //再释放内存
}
总结
关于new的三种使用方法已经介绍完了,虽然都是很小的知识点,但是确实很有用,如果本文有错误,欢迎大家交流指正,最后感谢你们可以认真地看完这篇博客,我会时常更新的哦。