第一部分: new和delete的实现原理
开始谈之前我们应该了解另一个概念“operator new”和“operator delete”:
new操作符调用一个函数来完毕必需的内存分配,你可以重写或重载这个函数来改变它的行为。new操作符为分配内存所调用函数的名字是operator new()。
函数operator new 通常这样声明:
void * operator new(size_t size);
返回值类型是void*,由于这个函数返回一个未经处理(raw)的指针。未初始化的内存。(假设你喜欢。你能写一种operator new函数,第二部分就是这样做的)。
注意点:
1.operator new是用来分配内存的函数,为new操作符调用。能够被重载.
2.你能添加额外的參数重载函数operator new,可是第一个參数类型必须是size_t。
-
内置类型
如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是:new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申请空间失败时会抛异常,malloc会返回NULL。 -
自定义类型
//new的原理
第一步: 调用operator new函数申请空间
第二部: 在申请的空间上执行构造函数,完成对象的构造//delete的原理
第一步: 在空间上执行析构函数,完成对象中资源的清理工作
第二步: 调用operator delete函数释放对象的空间//new T[N]的原理
第一步:调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请
第二步:在申请的空间上执行N次构造函数
//delete[]的原理
第一步:在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
第二步:调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间
第二部分:针对链表节点重载operator new 和operator delete 实现链表节点使用内存池申请和释放空间
#include<memory>
#include<iostream>
using namespace std;
struct ListNode{
ListNode* _prev;
ListNode* _next;
int _data;
void* operator new(size_t size)
{
void *p = nullptr;
p = allocator<ListNode>().allocate(10);
cout << "memory pool create OK!!!"<<endl;
return p;
}
void operator delete(void *p)
{
allocator<ListNode>().deallocate((ListNode*)p,10);
cout << "memory pool be deallocated !!!" << endl;
}
};
//带头的双向循环链表
class List
{
public:
List()
{
//这块尤其容易出错;一定要用正确的,合适的指针去更新
_head = new ListNode;
_head->_prev=_head;
_head->_next=_head;
}
~List()
{
ListNode* cur = _head->_next; //_head->next指向首元结点
while (cur != _head)
{
ListNode* next = cur->_next;
delete cur;
cur = next;
}
delete _head;
_head = nullptr;
}
private:
ListNode* _head;
};
int main()
{
List l1;
l1.List::List();//类外调用成员函数需要加作用域
l1.List::~List(); //程序会崩溃,原因是因为你显示的调用了List的析构函数,而程序退出时,又自动调用了一次
system("pause");
return 0;
}
通过调用发现我们这个时候如果针对ListNode节点使用new或者delete的时候,就会调用我们自己重载的operator new函数,输出相关的打印信息。