对new的认识
唉,基础不牢固就是要付出很多的努力才能弥补(T_T)
new在底层做的工作:
1)分配空间(operator new)
2)强制转换为对象
3)调用构造函数初始化
4)返回指针
尤其第一步,operator new,我们重载new操作符的时候是不是也是这样写的,当然这里也是一些教程没有写清楚,甚至大学老师都没有说清楚。其实我们重载的只是这个函数而已,并不是对整个操作符进行重载。
先看看new操作符重载的申明:
void* operator new(size_t size);
看出了什么?它返回void* 而不是object*,就代表我们只是重载了分配内存的地方,并没有重载其他的地方,而事实上我们也没有办法对整个new进行重载,原因在于第3步。
这里借用侯捷老师的代码:
void* p = operator new (size);
Complex * complex = static_cast<Complex *>(p);
complex->Complex::Complex(1, 2); //这里这一步,编译器是不会让你进行调用的,这里应该是编译器自己展开的。你如果写了这样的代码会直接报错,提示你无法调用它的构造函数,具体原因暂且不明,后面有机会接触到了再说
所以到现在,我们基本上可以说对new的重载只是重载了里面调用的一个函数,并没有对操作符完整重载,实质上还是函数的重载。
至于其他的操作符是不是一样的情况(除new / delete 系列外),还需要自己研究下,暂时先补这么一点吧。
---------------------------续上上次挖的坑--------------------------------------------
既然可以重载,定位内存泄漏如何呢?
#include <iostream>
using namespace std;
#include <map>
#include <string>
struct MemInfo
{
string file_name;
int line;
size_t size;
};
map<void *, MemInfo> memory_info;
void* operator new[](size_t size, string file_name, int line)
{
MemInfo mem_info;
mem_info.file_name = file_name;
mem_info.line = line;
mem_info.size = size;
void* mem = ::operator new(size);
memory_info.insert(make_pair(mem, mem_info));
return mem;
}
void* operator new(size_t size, string file_name, int line)
{
MemInfo mem_info;
mem_info.file_name = file_name;
mem_info.line = line;
mem_info.size = size;
void* mem = ::operator new(size);
memory_info.insert(make_pair(mem, mem_info));
return mem;
}
void operator delete[](void* mem, string file_name, int line)
{
map<void *, MemInfo>::iterator iter = memory_info.find(mem);
if (memory_info.end() != iter)
{
memory_info.erase(iter);
}
else
{
cerr << "no mem:" << mem << endl;
}
::operator delete(mem);
}
void operator delete(void* mem, string file_name, int line)
{
map<void *, MemInfo>::iterator iter = memory_info.find(mem);
if (memory_info.end() != iter)
{
memory_info.erase(iter);
}
else
{
cerr << "no mem:" << mem << endl;
}
::operator delete(mem);
}
#define new new(__FILE__, __LINE__) //这里虽然和定点new形式差不多,但它不是定点new哦
#define delete delete(__FILE__, __LINE__)
以上就是主要关键代码,在定义了自己的函数以后还不影响内存分配,这是最好的,下面测试一下?
void speak()
{
cout << "mem leak info:" << endl;
map<void *, MemInfo>::iterator iter = memory_info.begin();
for (; memory_info.end() != iter; ++iter)
{
cout << "file:" << iter->second.file_name << ", line:" << iter->second.line << ", addr:" << iter->first << ", size:" << iter->second.size << endl;
}
}
void main()
{
char* pArray = new char[100];
speak();
}
当然了,这里只是协助定位内存泄漏了,具体还需要输出的信息来分析是真的内存泄漏,还是这块内存是一个全局的变量等等。(定位死锁,内存泄漏都需要耐心,不要想着这些问题能够被直接输出出来)
上一篇: 实现可拖拽移动的悬浮按钮
下一篇: 移动端关于使用字体的思考