概述
- 通过重载 new 和 delete, 从而控制内存分配的过程.
- 执行 new 的过程:
- 编译器调用名为
operator new
(或operator new[]
)的标准库函数, 非配一块足够大, 原始, 未命名的内存空间. - 编译器运行相应构造函数, 并未其传入初始值.
- 返回一个指向该对象的指针.
- 执行 delete 的过程:
- 先执行相应的析构函数.
- 编译器调用名为
operator delete
(或operator delete[]
)的标准库函数释放内存空间.
- 编译器查找 new 和 delete 的顺序:
- 若操作对象是类类型, 则编译器首先在类或基类的作用域中查找. 若类中含 operator new (或 operator delete) 成员, 则调用这些成员.
- 编译器在全局作用域中查找匹配的函数, 若有自定义版本, 则使用.
- 若没找到, 则使用标准库定义的版本.
- 可以使用
::
(作用域运算符)忽略定义在类中的 new 或 delete 函数. eg: ::new
只在全局作用域中查找. - new 和 new[]. 使用以下示例说明:
new int
编译器解释为 new(sizeof(int))
.new int[10]
编译器解释为 new(sizeof(int) * 10)
.
- new 和 operator new 函数的区别 (delete 和 operator delete 类似):
- new 除了调用 operator new 函数, 还要调用构造函数.
- 我们平常说的重载 new, 其实只是重载 operator new 函数. 我们无法阻止之后调用构造函数的行为(也没必要阻止).
重载
- 我们可以在类中, 或是在全局作用域中定义自己版本的 operator new 和 operator delete.
- 当在类中定义 operator new 和 operator delete 时, 他们是隐式静态 的(也就是说, 无需显式声明 static, 不过最好还是声明吧, 保持统一性). 为什么是静态的呢? 因为 operator new 用于对象构造前, operator delete 用于析构后. 而且既然是静态的, 也就无法操作类的非静态数据成员了.
operator new 和 operator delete
- 可定义其他类型的 operator new.
void *operator new(size_t, void*);
该形式只供标准库使用, 不允许被用户重载.
void *operator new(size_t size) {
if (void *mem = malloc(size)) {
return mem;
} else {
throw bad_alloc();
}
}
void operator delete(void mem) noexcept {
free(mem);
}
内存泄漏检测
资料
实现
- MemInfoNode 用于记录申请的一块内存的信息. MemList 为一个单项链表, 存储每个申请的内存块的数据.
#define new new(__FILE__, __LINE__)
的作用是, 可以在代码中直接方便的使用 new, 不改变原来代码中的语法. eg: new int
将替换为new(__FILE__, __LINE__) int
. 编译器最后将调用 operator new(sizeof(int), __FILE__, __LINE__)
函数.- 在 MemList 中要使用 malloc 和 free. 防止使用 new, delete 造成的递归死循环.
#include <iostream>
using namespace std;
class MemInfoNode {
private:
void *pMem = NULL;
size_t memSize = 0;
const char *codeFile = NULL;
unsigned int codeLine = 0;
MemInfoNode *pNext = NULL;
void Print(ostream &out = std::cout) {
out << " FileName: " << codeFile
<< " LineNum: " << codeLine
<< " MemAddr: " << pMem
<< " MemSize: " << memSize
<< std::endl;
}
friend class MemList;
};
class MemList {
public:
MemList() {}
~MemList() {
MemInfoNode *nTmp = NULL;
while (m_pHeadNode) {
if (m_pHeadNode->pMem) {
free(m_pHeadNode->pMem);
}
nTmp = m_pHeadNode->pNext;
free(m_pHeadNode);
m_pHeadNode = nTmp->pNext;
}
}
bool Prepend(void *pMem, size_t memSize, const char *fileName, unsigned int lineNo) {
if (!pMem) {
return false;
}
MemInfoNode *pNode = (MemInfoNode*)malloc(sizeof(MemInfoNode));
pNode->pMem = pMem; pNode->memSize = memSize; pNode->codeFile = fileName; pNode->codeLine = lineNo;
pNode->pNext = m_pHeadNode; m_pHeadNode = pNode;
return true;
}
bool Remove(void *ptr) {
if (!ptr) {
return false;
}
MemInfoNode *n_pIt = m_pHeadNode;
MemInfoNode *n_pPtr = NULL;
while (n_pIt) {
if (n_pIt->pMem == ptr) {
if (!n_pPtr) {
m_pHeadNode = n_pIt->pNext;
}
else {
n_pPtr->pNext = n_pIt->pNext;
}
free(n_pIt);
return true;
}
n_pPtr = n_pIt;
n_pIt = n_pIt->pNext;
}
return false;
}
friend ostream & operator << (ostream &out, MemList obj);
void Result(ostream &out = std::cout) {
if (!m_pHeadNode) {
out << "[OK] This Application no memory leak!" << std::endl;
}
else {
out << "[ERR] This Application have memory leak!" << std::endl;
MemInfoNode *n_pIt = m_pHeadNode;
while (n_pIt) {
n_pIt->Print(out);
n_pIt = n_pIt->pNext;
}
}
}
private:
MemInfoNode *m_pHeadNode = NULL;
};
ostream & operator << (ostream &out, MemList obj) {
obj.Result(out);
return out;
}
MemList mem_list;
void *operator new(size_t size, const char *fileName, unsigned int lineNo){
void *pMem = malloc(size);
if (pMem) {
mem_list.Prepend(pMem, size, fileName, lineNo);
}
return pMem;
}
void *operator new[](size_t size, const char *fileName, unsigned int lineNo){
return operator new(size, fileName, lineNo);
}
void operator delete(void *pMem) {
if (pMem) {
free(pMem);
mem_list.Remove(pMem);
}
}
void operator delete[](void *pMem) {
operator delete(pMem);
}
#define new new(__FILE__, __LINE__)
void Test_bad_code() {
int *p1 = new int;
int *p2 = new int;
int *p3 = new int[10];
int *p4 = new int[20];
delete p1;
delete []p3;
}
void Test_good_code() {
int *p1 = new int;
int *p2 = new int;
int *p3 = new int[10];
int *p4 = new int[20];
delete p1;
delete p2;
delete []p3;
delete []p4;
}
int main()
{
Test_good_code();
Test_bad_code();
mem_list.Result();
int tmp;
cin >> tmp;
return 1;
}