对 malloc free ,new,delete 的考虑与探索——2

对 malloc free ,new,delete 的思考与探索——2

一.重载全局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());
	}
}
上边的输出结果是

对 malloc free ,new,delete 的考虑与探索——2


对类类型,delete一个数组时(比如,delete []sa;),要为每一个数组元素调用析构函数。但对于delete表达式(比如,这里的delete []sa),它并不知道数组的元素个数(只有new函数和delete函数知道)。因此,必须有一种手段来告诉delete表达式的数组大小是多少。那么一种可行的方式就是,多分配一个大小为4字节的空间来记录数组大小,并可以约定前四字节来记录大小。那么,由new函数分配的地址与new表达式返回的地址应该相差4个字节(这可以写程序来验证)。对于非类类型数组和不需要调用析构函数的类类型数组,这多于的四字节就不需要了

可以在vc6.0上边调试一下,如下图:

对 malloc free ,new,delete 的考虑与探索——2

二.对于一个类重载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];
	}
	  
}



版权声明:本文为博主原创文章,未经博主允许不得转载。