内存泄漏追踪器
operator new 和 operator delete是两个全局函数,new/delete底层调用它们,所以我们可以模拟实现这两个全局函数,起到追踪内存的创建和销毁。已知优先调用:类成员函数>全局函数>系统函数;
class Date
{
private:
int _year;
int _month;
int _day;
public:
Date(int year = 1990, int month = 1, int day = 1)
{
this->_year = year;
_month = month;
_day = day;
}
void *operator new(size_t size, const char* FileName, const char *FuncName, size_t LineNo)
{
cout << FileName << "-" << FuncName << "-" << LineNo << endl;
void *p = ::operator new(size);
return p;
}
};
//返回值必须是void*,第一个参数必须是size
//这个函数主要处理内置类型
void *operator new(size_t size, const char* FileName, const char *FuncName, size_t LineNo)
{
cout << FileName << "-" << FuncName << "-" << LineNo << endl;
void *p = ::operator new(size);
return p;
}
void operator delete(void *p, const char* FileName, const char *FuncName, size_t LineNo)
{
cout << FileName << "-" << FuncName << "-" << LineNo << endl;
::operator delete(p);
}
//放到后面
#define new new(__FILE__,__FUNCDNAME__,__LINE__)
#define delete(p) operator delete(p,__FILE__,__FUNCDNAME__,__LINE__)
int main()
{
Date *p = new Date;
delete(p);
int *pp = new int;
delete(pp);
return 0;
}
内存池
如果我们实现一个双向链表,每申请一个链表节点,都需要malloc或者new,又因为他两会多申请36个字节,所以整个链表下来,会造成内存特别浪费,而且效率也不咋地,所以有了内存池。内存池就是我们申请一块特别大的空间,当我们需要的时候进行从内存池取出空间,一般内存池和定位new搭配使用。
struct ListNode
{
ListNode* _next;
ListNode* _prev;
int _data;
void* operator new(size_t n)
{
void* p = nullptr;
p = allocator<ListNode>().allocate(1);
cout << "memory pool allocate" << endl;
return p;
}
void operator delete(void* p)
{
allocator<ListNode>().deallocate((ListNode*)p, 1);
cout << "memory pool deallocate" << endl;
}
};
class List
{
public:
List()
{
_head = new ListNode;
_head->_next = _head;
_head->_prev = _head;
}
~List()
{
ListNode* cur = _head->_next;
while (cur != _head)
{
ListNode* next = cur->_next;
delete cur;
cur = next;
}
delete _head;
_head = nullptr;
}
private:
ListNode* _head;
};
int main()
{
List l;
return 0;
}