new/delete不完全手册
--------------------------------------------------------
这是一份未完成的文档,本来想等完全完成后再贴出,可是我发现如果我不是写一点就贴一点的话,那么永远都没有完成的时候了。
我争取让一个人看了这个帖子可以学会所有和new/delete有关的知识。
我会不断补充的,需要知道什么,有什么问题,也请告诉我。(论坛消息)
0
我们在C++里面在堆上创建一个对象的时候,通常使用的方法就是new。譬如说,下面这段代码创建了一个具有两个元素的T的数组。
我们平时说的new,从概念上说,可分为new operator和operator new。上述程序里面的这个new就是new operator,new operator调用operator new分配内存,然后再调用对象的构造函数。你是不能去重载new operator的,你只能重载operator new。也就是说,你只能干预对象的内存是怎么分配的,但是你不能干预对象创建的过程。标准文献上从未有类似于delete operator的记载,但是我们可以认为delete也分为delete operator和operator delete;前者先调用析构函数,再调用后者释放内存。下面我们说起new/delete的时候,应该可以根据上下文判断所说的是什么。
所有的operator new/operator delete成员函数,都是static的,即使你没有写static。operator new/operator delete和普通成员函数一样,可以被继承,可以被显式调用,会被掩盖。
1
new T;
其过程是:首先,调用T:

perator new(如果没有定义的话,可以认为编译器会给出一个缺省定义。)分配内存,然后再对这个新分配的内存调用T的ctor。
如果调用T:

perator new的时候,有异常抛出,则ctor不会被调用,而且该异常会继续向上抛出。如果调用ctor的时候抛出异常,那么会调用T:

perator delete来释放这段内存,并且异常会被向上抛出。(
T::dtor不会被调用)
如果调用T:

perator new的时候,返回NULL,则ctor不会被调用,返回NULL。但是,如果你要让你的T:

perator new返回NULL,你应该把它的exception specification写成throw();否则就应该在错误的情况下抛出std::bad_alloc。
返回NULL的情况写成代码如下:
代码:
T* p=(T*)T::operator new(sizeof(T));
if(!p)
{
try
{
p->T::T();
}
catch(...)
{
T::operator delete(sizeof(T));
throw;
}
}
return p;
2
new T[x];
其过程是:首先,调用T:

perator new[](如果没有定义的话,可以认为编译器会给出一个缺省定义。
注意,不是调用多次T:
perator new或者以size*x来调用一次T:
perator new)分配内存,然后再对这个新分配的内存中的每个T调用T的ctor。(从第一个起,到最后一个。)
如果在调用T:

perator new[]的时候,有异常抛出,那么后面的ctor将不会被调用到。异常会被向上抛出。
如果调用某个ctor的时候,有异常抛出,那么这个对象的dtor将不会被调用,而会对前面已经调用过ctor的对象调用dtor,其方向是从最后一个被初始化的起到第一个。然后调用T:

perator delete[]释放内存并将异常向上抛出。
注意,operator new[]的size参数会>=所要分配的对象的size*个数。
譬如说:
T* t=new T[3];在调用t[2]的ctor的时候抛出异常,那么会先调用t[1]的dtor,再调用t[0]的dtor,再调用T:

perator delete[],然后再把这个异常向上抛出。
写成代码如下:
代码:
char* pc=T::operator new[](sizeof(T)*x+MARK_SIZE);
T* p=(T*)(pc+MARK_SIZE);
int i;
try
{
for(i=0;i<x;++i)
p[i].T::T();
}
catch(...)
{
--i;
while(i>=0)
p[i].T::~T();
T::operator delete[](pc);
throw;
}
return p;
3
delete T;
很简单,先调用dtor,再释放内存。如果调用dtor的时候有异常抛出,那么继续向上抛,不释放内存。
4
delete[] T;
先反向调用dtor,再释放内存。如果调用dtor的时候有一个异常抛出,那么继续调用下面的dtor,然后再向上抛,内存不会被释放。如果在继续调用下面的dtor的时候,又有异常产生,bad_exception。
写成代码如下:
代码待补充 5
为什么delete/new和delete[]/new[]要配对使用。
解释待补充
class SomeClass
{
public:
void* operator new[](size_t size)
{
cout<<size<<endl;
return NULL;
}
};
int main()
{
SomeClass objects[2];
cout<<sizeof(SomeClass)<<endl;
cout<<sizeof(objects)<<endl;
new SomeClass[2];
return 0;
}
6
new(nothrow) T;
7
new

T;
8 operator new and
new operator 9
一些有趣的应用:
a.让一个类ctor发生异常,new返回NULL。
b.让一个类只能用new创建。
......
Reference:
The C++ PL, by Bjarne Stroustrup
ISO 14882
ECPP/MECPP CD, by Scott Meyer