一.重载全局new 和delete
当重载全局版的new和delete的时候,使默认的版本就不能调用
#include<cstdio>
#include<new>
#include <cstdlib>
void* operator new(size_t sz)throw(std::bad_alloc)//这个就是我们使用的默认new,也就是plain new在分配失败的情况下,抛出异常std::bad_alloc而不是返回NULL,因此通过判断返回值是否为NULL是徒劳的。
{//返回一个指向等于或者大于(大于有原因)的对象的指针,如果找不到存储单元,返回零,再显示异常信息之类
//cout<<"operator new: "<<sz<<"Bytes"<<endl;
printf("operator new %d Bytes\n",sz);
//注意这里使用printf和puts并没有使用iostream因为当建立iostream的对象(cin,cout,cerr)他们去调用new去分配内存,就会进入死锁状态,而用printf不会,因为他不用new来初始化本省
void* m = malloc(sz);
if(!m)
puts("out of memory");
return m;
}//返回值是一个void*不是指向特定任何类型的指针,所做的工作就是分配内存,不是完成一个对象的建立,对象的建立指导构造函数调用才完成,这是编译器所做的工作,不再我们的控制范围之内
void operator delete(void* m)throw()//参数是一个指向operator new 分配内存的指针void*
{
puts("operator delete");
free(m);
}//参数是void*是因为它是在调用析构函数后的到的指针,析构函数从存储单元里移去对象,operator delete返回值是void
class s
{
public:
s(int n=0):i(n)
{
puts("s::s()\n");
}
~s()
{
puts("s::~s()\n");
}
private:
int i;
};
void main()
{
try{
puts("creating & destroying an int");
int *p = new int(47);
delete p;
puts("creating & destroying an s");
s *ss =new s;
delete ss;
puts("creating & destroying an s[3]\n");
s *s1 = new s[10];//多出来的4字节用于记录有多少个实例对象
//上限是4294967295,也就是无符号整型的最大值加一就又是0
delete []s1;
int* pi=new int[3];
delete []pi;
}
catch(std::bad_alloc &ex)
{
puts(ex.what());
}
}
上边的输出结果是
对类类型,delete一个数组时(比如,delete []sa;),要为每一个数组元素调用析构函数。但对于delete表达式(比如,这里的delete []sa),它并不知道数组的元素个数(只有new函数和delete函数知道)。因此,必须有一种手段来告诉delete表达式的数组大小是多少。那么一种可行的方式就是,多分配一个大小为4字节的空间来记录数组大小,并可以约定前四字节来记录大小。那么,由new函数分配的地址与new表达式返回的地址应该相差4个字节(这可以写程序来验证)。对于非类类型数组和不需要调用析构函数的类类型数组,这多于的四字节就不需要了
可以在vc6.0上边调试一下,如下图:
二.对于一个类重载new和delete
为一个类中重载new和delete和重载其他运算符一样。当编译器看到使用new创建自己定义的类的对象的时候他选择成员版本的operator new()而不是全局的new,但是全局版本的new和delete仍为所有其他类型对象使用(除非他们自己有new和delete)
因为没有涉及到全局的new和delete所以不在乎iostream调用new产生自己的对象产生死锁现象
#include <iostream>
using namespace std;
class Framis
{
public:
enum{psize = 2};
Framis()
{
puts("Framis()");
}
~Framis()
{
puts("~Framis()");
}
void* operator new(size_t s)throw(std::bad_alloc);
void operator delete(void* m);
private:
enum{ sz =10};
char c[sz];
static unsigned char pool[];
static bool alloc_map[];
};
unsigned char Framis::pool[psize*sizeof(Framis)];
bool Framis::alloc_map[psize] = {false};
void* Framis::operator new(size_t s)throw(std::bad_alloc)
{
for(int i=0;i<psize;++i)
{
if(!alloc_map[i])
{
cout<<"using block "<<i<<".....";
alloc_map[i]= true;
return pool + (i * sizeof(Framis));
}
}
//cout<<"out of memory\n";
throw bad_alloc();
}
void Framis::operator delete(void* m)throw()
{
if(!m)//check for null pointer
return ;
unsigned char block =(unsigned char)m-(unsigned char)pool;
block/=sizeof(Framis);
cout<<"freeing block "<<block<<endl;
//free (m);
alloc_map[block] = false;
}
void main()
{
Framis * f[Framis::psize];
try
{
for(int i =0;i<Framis::psize;++i)
{
f[i] = new Framis;
}
new Framis;//out of memory
}
catch(std::bad_alloc)
{
cerr<<"out of memory! "<<endl;
}
//delete f;
//f[10]=0;
Framis *x = new Framis;
delete x;
for(int j=0;j<Framis::psize;++j)
{
delete f[j];
}
}