欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

对new的认识

程序员文章站 2024-03-15 20:03:12
...

唉,基础不牢固就是要付出很多的努力才能弥补(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();
}

对new的认识
当然了,这里只是协助定位内存泄漏了,具体还需要输出的信息来分析是真的内存泄漏,还是这块内存是一个全局的变量等等。(定位死锁,内存泄漏都需要耐心,不要想着这些问题能够被直接输出出来)