共计 2073 个字符,预计需要花费 6 分钟才能阅读完成。
一、概念
在 C ++ 中 new 的三种用法包括:plain new,nothrow new 和 placement new。
plain new 就是我们最常使用的 new 的方式,在 C ++ 中的定义如下:
1 void* operator new(std::size_t) throw(std::bad_alloc);
2 void operator delete(void *) throw();
plain new 在分配失败的情况下,抛出异常 std::bad_alloc 而不是返回 NULL,因此通过判断返回值是否为 NULL 是徒劳的。
nothrow new 是不抛出异常的运算符 new 的形式。nothrow new 在失败时,返回 NULL。定义如下:
1 void * operator new(std::size_t, const std::nothrow_t&) throw();
2 void operator delete(void*) throw();
placement new 意即“放置”,这种 new 允许在一块已经分配成功的内存上重新构造对象或对象数组。placement new 不用担心内存分配失败,因为它根本不分配内存,它做的唯一一件事情就是调用对象的构造函数。定义如下:
1 void* operator new(size_t, void*);
2 void operator delete(void*, void*);
palcement new 的主要用途就是反复使用一块较大的动态分配的内存来构造不同类型的对象或者他们的数组。placement new 构造起来的对象或其数组,要显示的调用他们的析构函数来销毁,千万不要使用 delete。
二、示例
plain new
char *getMemory(unsigned long size)
{
char * p = new char[size];
return p;
}
void main(void)
{
try{
char * p = getMemory(1000000); // 可能发生异常
// …
delete [] p;
}
catch(const std::bad_alloc & ex)
{
cout << ex.what();
}
}
nowthrow new
void func(unsinged long length)
{
unsinged char * p = new(nothrow) unsinged char[length];
// 在使用这种 new 时要加 (nothrow),明示不使用异常处理。
if (p == NULL) // 因不抛异常,故定要检查
cout << “allocte failed !”;
// …
delete [] p;
}
placement new
void main()
{
using namespace std;
char * p = new(nothrow) char [4];
if (p == NULL)
{
cout << “allocte failed” << endl;
exit(-1);
}
// …
long * q = new (p) long(1000);
delete []p; // 只释放 p,不要用 q 释放。
}
p 和 q 仅仅是首址相同,所构建的对象可以类型不同。所“放置”的空间应小于原空间,以防不测。当”放置 new”超过了申请的范围,Debug 版下会挂机,但 Release 版竟然能运行而不出错!该运算符的作用是:只要第一次分配成功,不再担心分配失败。
void main()
{
using namespace std;
char * p = new(nothrow) char [100];
if (p == NULL)
{
cout << “allocte failed” << endl;
exit(-1);
}
long * q1 = new (p) long(100);
// 使用 q1 …
int * q2 = new (p) int[100/sizeof(int)];
// 使用 q2 …
ADT * q3 = new (p) ADT[100/sizeof(ADT)];
// 使用 q3 然后释放对象 …
delete [] p; // 只释放空间,不再析构对象。
}
注意:使用该运算符构造的对象或数组,一定要显式调用析构函数,不可用 delete 代替析构,因为 placement new 的对象的大小不再与原空间相同。
void main()
{
using namespace std;
char * p = new(nothrow) char [sizeof(ADT)+2];
if (p == NULL)
{
cout << “allocte failed” << endl;
exit(-1);
}
// …
ADT * q = new (p) ADT;
// …
// delete q; // 错误
q->ADT::~ADT(); // 显式调用析构函数,仅释放对象
delete [] p; // 最后,再用原指针来释放内存
}
placement new 的主要用途就是可以反复使用一块已申请成功的内存空间。这样可以避免申请失败的徒劳,又可以避免使用后的释放。特别要注意的是对于 placement new 绝不可以调用的 delete, 因为该 new 只是使用别人替它申请的地方(只是个租房户,不是房主。无权将房子卖掉)。释放内存是 nothrow new 的事,即要使用原来的指针释放内存。