对 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()); } }上边的输出结果是
对类类型,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]; } }
版权声明:本文为博主原创文章,未经博主允许不得转载。