运算符重载、内存池、智能指针

内存池:为了解决频繁开辟内存、释放内存的效率问题和碎片问题。

             效率问题:因为要每次开辟内存释放内存都要从用户态切换到内核态,状态的转换需要时间,                                                                         需要尽可能地避免。                        

             碎片问题:由于系统分配内存无法得知未来的内存分配布局,所以不可避免地会产生内存碎片。

对象的开辟:分两步:

                                 1、开辟空间:调用operator new()函数

                                 2、调用构造函数来对所开辟的空间初始化。

通用内存池的实现:

                     申请一块大的内存区域,然后自主分配内存的使用,就可以避免上述问题的发生。

               内存池应和对象分离,尽可能地,我们应使用面向对象的思想,所以,我们可以将内存池封装成类;结合两种                           说法就是:将管理交给内存池来实现,对外只需要提供两个接口来模拟new和delete关键字。

                 为了方便内存管理,这里最好选用静态链表的方式进行组织,因为内存随时需要变动,所以需要使用链表,但                          又是我们管理已知大小和方式的类型,所以可以使用数组的方式存储,,相结合最好的管理方式就是静态链表。

               静态链表的内存布局:多个数据域加指针域构成的结点域所组成的数组来管理,在内存池中应该模拟真实内存分配:即            分配出去的内存交给用户来管理,而未使用部分则交给内存池来管理,本来应该将内存池分为这两部分,而仔细思考下其            实由内存池管理的只有未使用部分,所以,只需一个指针指向未使用部分的头即可,还有要做的就是当用户delete时需要              可以把还回来的内存重新链接回去。

                 数据结构设计完毕后到了函数设计部分了:

                         1、alloc()函数:首先,开始,判断未使用部分的指针是否为NULL,若为                  NULL,则需要开辟空                           间,并以传入的数据结构大小加上指针域大小进行初始化。

                         2、delalloc()函数:模拟头插或者尾插的实现方式,将外部的一个内存区域链入到未使用的部分。

代码如下:

#include<iostream>
using namespace std;

const int MEM_SIZE = 2;

template<typename T>
class MEM_POOL
{
public:
	MEM_POOL():pool(NULL){}

	void* alloc(size_t size)
	{
		if(pool == NULL)
		{
			pool = (Node*) new char[(size + 4) * MEM_SIZE];
			Node* pCur = pool;
			for(;pCur < pool + MEM_SIZE - 1;++pCur)
			{
				pCur->pnext = pCur + 1;
			}
			pCur->pnext = NULL;
		}
		Node* rt = pool;
		pool = pool->pnext;
		return rt;
	}
	void dealloc(void* ptr)
	{
		if(ptr == NULL)
			return;
		((Node*)ptr)->pnext = pool;
		pool = (Node*)ptr;
	}
private:
	class Node
	{
	public:
		Node(T val = T()):mdata(val),pnext(NULL){}
	public:
		T mdata;
		Node* pnext;
	};
	Node* pool;
};

class Stu
{
public:
	Stu(char* name,int mage):mname(new char[strlen(name)+1]),age(mage)
	{
		strcpy(mname,name);
	}
	void* operator new(size_t size)
	{
		return mpool.alloc(size);
	}
	void operator delete(void* ptr)
	{
		mpool.dealloc(ptr);
	}
	~Stu()
	{
		delete []mname;
		mname = NULL;
	}
private:
	char* mname;
	int age;
	static MEM_POOL<Stu> mpool;
};

MEM_POOL<Stu> Stu::mpool;

int main()
{
	Stu* pstu1 = new Stu("zhangsan",10);
	Stu* pstu2 = new Stu("lisi",11);
	Stu* pstu3 = new Stu("wangwu",12);
	Stu* pstu4 = new Stu("maliu",13);
	delete pstu1;
	delete pstu2;
	delete pstu3;
	delete pstu4;

	int *p = (int*)malloc(4);
	double* p2 = (double*)malloc(8);

	int *p3 = (int*) malloc(8);
	int a = (int)p;
	a += 1;
	p = (int*)a;
	free(p);
	free(p2);
	free(p3);
	return 0;
}

free的内存释放机制:malloc需要调用底层的接口,系统调用硬件资源开辟内存,malloc接收用户输入的内存大小,系统当然也         会得到,所以,系统会维护一个数据结构,维护返回的地址和开辟的大小,而free时,拿地址和数据结构的存储里面匹配,如       果匹配了,就把size大小的大小释放,如果未匹配到,就报错,程序崩溃。

使用单例模式实现内存池:

            因为每种类型的内存池只需要存在一个来管理即可,一个内存池就可以管理任意多个同类型数据,所以,通过模板实例          化的类都只需要实例化生成一个对象即可,这种情况,用单例模式恰到好处。

代码实现:

#include<iostream>
using namespace std;

const int MEM_SIZE = 2;

template<typename T>
class MEM_POOL
{
public:
	static MEM_POOL* getInstance()
	{
		return &mempool;
	}
	void* alloc(size_t size)
	{
		if(pool == NULL)
		{
			pool = (Node*) new char[(size + 4) * MEM_SIZE];
			Node* pCur = pool;
			for(;pCur < pool + MEM_SIZE - 1;++pCur)
			{
				pCur->pnext = pCur + 1;
			}
			pCur->pnext = NULL;
		}
		Node* rt = pool;
		pool = pool->pnext;
		return rt;
	}
	void dealloc(void* ptr)
	{
		if(ptr == NULL)
			return;
		((Node*)ptr)->pnext = pool;
		pool = (Node*)ptr;
	}
private:
	MEM_POOL():pool(NULL){}
	MEM_POOL(const MEM_POOL<T>&);
	class Node
	{
	public:
		Node(T val = T()):mdata(val),pnext(NULL){}
	public:
		T mdata;
		Node* pnext;
	};
	Node* pool;
	static MEM_POOL<T> mempool;
};
template<typename T>
MEM_POOL<T> MEM_POOL<T>::mempool;
class Stu
{
public:
	Stu(char* name,int mage):mname(new char[strlen(name)+1]),age(mage)
	{
		strcpy(mname,name);
	}
	void* operator new(size_t size)
	{
		return mpool->alloc(size);
	}
	void operator delete(void* ptr)
	{
		mpool->dealloc(ptr);
	}
	~Stu()
	{
		delete []mname;
		mname = NULL;
	}
private:
	char* mname;
	int age;
	static MEM_POOL<Stu>* mpool;
};

MEM_POOL<Stu>* Stu::mpool = MEM_POOL<Stu>::getInstance();

int main()
{
	Stu* pstu1 = new Stu("zhangsan",10);
	Stu* pstu2 = new Stu("lisi",11);
	Stu* pstu3 = new Stu("wangwu",12);
	Stu* pstu4 = new Stu("maliu",13);
	delete pstu1;
	delete pstu2;
	delete pstu3;
	delete pstu4;

	MEM_POOL<Stu>* spool1 = MEM_POOL<Stu>::getInstance();
	MEM_POOL<Stu>* spool1 = MEM_POOL<Stu>::getInstance();
	MEM_POOL<Stu>* spool1 = MEM_POOL<Stu>::getInstance();
	MEM_POOL<Stu>* spool1 = MEM_POOL<Stu>::getInstance();
	/*int *p = (int*)malloc(4);
	double* p2 = (double*)malloc(8);

	int *p3 = (int*) malloc(8);
	int a = (int)p;
	a += 1;
	p = (int*)a;
	free(p);
	free(p2);
	free(p3);
	return 0;*/
}

运算符重载之智能指针:

        堆栈的区别:

                栈:系统开辟     系统释放

                堆:手动开辟      手动释放

        智能指针:类的析构函数就是C++设计的由系统自动释放堆上资源的方式,所以,我们可以通过构造类,来实现系统自动回      收堆上的内存。

 

#include<iostream>
using namespace std;

int Compare(int a)
{
	int* p = new int();
	if(*p == a)
	{
		return 0;
	}
	delete p;
	return a;
}

template<typename T>
class SmartPtr
{
public:
	SmartPtr(T* ptr = NULL):mptr(ptr){}
	SmartPtr(const SmartPtr&rhs):mptr(rhs.mptr)//拷贝构造容易造成重复析构的问题:
		//解决办法1:管理权唯一(只有一个对象指向对应内存块,其他的一旦调用拷贝构造就指向NULL)
	{
		rhs.Release();
	}
	SmartPtr<T>&operator=(const SmartPtr<T>& rhs)
	{
		if(this != &rhs)
		{
			delete mptr;
			mptr = rhs.mptr;
			rhs.Release();
		}
		return *this;
	}
	T&operator*()
	{
		return *mptr;
	}
	T* operator->()
	{
		return mptr;
	}
	~SmartPtr()
	{
		delete mptr;
		mptr = NULL;
	}
private:
	void Release()const
	{
		(T*)mptr = NULL;
	}
	T* mptr;
};

class Test
{
public:
	Test(int a):ma(a){}
	void Show()
	{
		cout<<ma<<endl;
	}
private:
	int ma;
};

int main()
{
	int* p = new int;
	SmartPtr<int> sp1(p);
	SmartPtr<int> sp2(sp1);
	sp1 = sp2;

	Test* ptest = new Test(30);
	ptest->Show();

	SmartPtr<Test>sp3(ptest);
	sp3->Show();//指向运算符是一个单目运算符,因为其无法判断右边的类型是否是一个变量还是一个函数,所以返回值只和左边的参数有关
	return 0;
}

 友元关系:

        1、函数友元

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值