C++编程思想--动态创建对象(2)

动态创建对象(2)

  5)重载new delete,首先为什么需要重载newdelete呢?

① 也许要创建和销毁一个类的非常多的对象,以至于这个影响到了速度。

② 分配不同大小的内存可能会产生碎片,内存很快就被分配完

所以重载的时候我们只是改变了原来的分配方法,当重载时可以替换原来内存消耗完之后的行为。所以在operator new 中要决定是返回0,还是调用new-hander的循环。或者产生异常的消息。我们可以选择重载全局内存分配函数或者是针对于某个类。

(1)这是重载全局的new以及delete之后的程序以及运行结果:

#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;

void * operator new(size_t sz)//1.size_t 的类型是?标准C库中定义的,应为unsigned int,它是一种“整型”类型,
{                             //里面保存的是一个整数,就像int, long那样。

	//printf("operator new :%d Bytes\n",sz);//2.这里使用的是printf,而不是cout,因为它是一个iostream对象,会调用new去分配内存,于是产生死锁
	cout<<"operator new "<<sz<<endl;
	void *m=malloc(sz);//3.申请空间返回的是void* 类型,所以它所做的只是分配内存,而非完成一个对象的创建。对象的创建要等到编译器调用构造函数才完成
	if (!m)
	{
		puts("out of memeory");
	}
	return m;
}

void operator delete(void *m)//参数是void* 这是调用析构函数后得到的指针,也就是说析构函数会从构造函数中获得内存的指针
{                            //返回类型为void
     puts("operator delete");
	 free(m);
}



class S
{
	int i[100];
public:
	S()
	{
		puts("S::S()");//
	}
	//void operator delete[](void *m)//这种方式可以删除对象数组
	//{
	//	puts("operator array delete");
	//	::delete []m;
	//}
	~S()
	{
		puts("S::~S()");
	}
};

int GlobalOperatorNewTest()
{
	puts("creating & destorying an int");
	int *p=new int(47);
	delete p;
	puts("creating &destorying an S");
	S *s=new S;
	delete s;
	puts("creating &destorying S[3]");
	S *sa=new S[3];//4.这里会多出空间,用于存放数组的信息,也就是说对象的数量的信息。
	delete []sa;
	return 0;
}

结果:


从结果中我们可以看到首先会调用new然后再调用的是构造函数。调用了析构函数之后才会调用deleted函数。但是我们看到在释放对象数组的时候并没有调用我们自己定义的deleted函数。而是调用的系统的delete[],

那么如果在类中对数组进行delete的重载如下:

void operator delete[](void *m)//这种方式可以删除对象数组
	{
		puts("operator array delete");
		::delete []m;
	}

这是进行重载数组的delete函数之后的执行结果

(1)也可以在类中进行new的重载,只是针对这个类。

代码:

//operator new local
#include <cstddef>
#include <fstream>
#include <iostream>
#include <new>

using namespace std;
ofstream out("Framis01.txt");

class Framis
{
	enum{sz=10};
	char c[sz];
	static unsigned char pool[];
	static bool alloc_map[];
public:
	enum{prize=100};
	Framis()
	{
		out<<"Framis()\n";
	}
	~Framis()
	{
		out<<"~Framis()...";
	}
	#pragma   warning(   disable   :   4290   )   
	void *operator new (size_t) throw(bad_alloc);
	void operator delete(void *);
};

unsigned char Framis::pool[prize*sizeof(Framis)];
bool Framis::alloc_map[prize]={false};
void * Framis::operator new(size_t )throw(bad_alloc)//参数后面带throw告诉编译器可以产生一个bad_alloc的异常消息。且若没有内存可以使用,也会由
{                                                    //bad_alloc产生一个异常消息。
  //使用类的这种创建方法,可以减少内存碎片。那么释放掉的内存可以重新使用
	for (int i=0;i<prize;i++)
	{
		if(!alloc_map[i])//判断这块内存有没有被使用,
		{
			out<<"using block"<<i<<"...";
			alloc_map[i]=true;//没有使用的话,将其置为true
			return pool+(i*sizeof(Framis));//返回地址
		}
	}
	cout<<"out of memeory"<<endl;
	throw bad_alloc();
}

void Framis::operator delete(void *m)
{
	if(!m)//确保是地址在堆内是在正确的地址范围之内,因为很可能我们删除的是数组,然而忘记加上[]。
		return;
	unsigned long block=(unsigned long)m-(unsigned long)pool;
	block/=sizeof(Framis);
	out<<"freeing block  "<<block<<endl;//释放对应的地址空间.
	alloc_map[block]=false;
}

int main()
{
	Framis *f[Framis::prize];
	try{
		for (int i=0;i<Framis::prize;i++)
		{
			f[i]=new Framis ;
		}
		new Framis;
	}catch(bad_alloc)//在这里接收内存申请失败的信息。
	{
		cerr<<"Out of memory!"<<endl;
	}
	delete f[10];//这是调用全局版本的delete.
	f[10]=0;//删除对应的空间内容,并且使这个指针的值为0.
	Framis *x=new Framis;//当重新创建一个对象,对象的内容将会被放在f[10]所指的内存中,这样就充分的利用资源
	delete x;
	for (int j=0;j<Framis::prize;j++)
	{
		delete f[j];
	}
}

运行结果:

可以看到释放的内存重新被利用起来。下面是txt中的一部分内容

using block99...Framis()

~Framis()...freeing block  10

using block10...Framis()

~Framis()...freeing block  10

(1)定位new.也就是确定在哪个位置上进行分配内存,也就是可以向New函数中传递参数,但是对于delete是不能传递的,它是与new对应的。

小结:

1、C中的malloc虽然可以使用但是不安全,

2、如果对内存要求很高的时候我们不妨使用自己定义的new来申请内存空间



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值