您的位置:首页 > 编程语言 > C语言/C++

C++动态内存管理核心知识点总结

2017-03-12 01:35 148 查看
动态内存管理核心:



首先,我们来重载一下operator new ();进行预处理,给我们打印一些有用的 信息,比如:当前定位的行号,开辟空间的大小(方便我们对于内存泄漏的检查)

#include<iostream>
using namespace std;

class Test
{
public:
Test()
{
cout << "Test()" << endl;
}
~Test()
{
cout << "Test()" << endl;
}

private:
int _data;
};

void* operator new(size_t size, const char*fileName, const char*funcName, int lineNo)
{
cout << fileName << ":" << funcName << "--" << lineNo << endl;
cout << size <<endl;
return malloc(size);
}
#if _DEBUG
#define new new(__FILE__,__FUNCDNAME__,__LINE__)
#endif
//此时需要对operator new 进行重载,系统中没有合适的operator new

void FunTest()
{
Test*p = new Test;
}

int main()
{

FunTest();
return 0;
}


效果如图所示:



下来,我们对new/delete 和new[]和delete[]进行仿写,了解一下底层实现

#include<iostream>
using namespace std;

class Test
{
public:
Test()
{
cout << "Test()" << endl;
}
~Test()
{
cout << "~Test()" << endl;
}

private:
int _data;
};

Test* New(size_t size)
{
Test* p = (Test*)malloc(size);
if (NULL == p)
{
return p;
}
//执行构造函数
new(p)Test;//定位new 表达式执行构造函数
return p;
}

//delete ->析构函数-》释放空间
void Delete(Test*p)
{
//要调用函数,那就要对调用它的指针进行判空处理
if (p)
{
p->~Test();
free(p);
}
}

//new[]-->malloc
//多开辟四个字节来保存数组数量
Test* NewArray(size_t count)
{
int *p = (int *)malloc(count + 4);
//malloc之后就要对返回值进行判空处理
if (p == NULL)
{
//return p;//直接返回p与声明类型不一致
return NULL;
}

*p = count;
//p = (Test*)(p + 1);->类型不匹配,我们重新定义一个指针
Test* pt = (Test*)(p + 1);

for (size_t idx = 0; idx < count; ++idx)
{
//使用定位new表达式
new(pt + idx)Test;
}
return pt;//返回起始构造函数的位置
}

//delete[]
void DeleteArray(Test*p)
{
//分情况-》空,不空
if (p == NULL)
{
return;
}
int count = *((int *)p - 1);

//从后往前析构

for (int idx = count - 1; idx >= 0; --idx)
{
(p + idx)->~Test();
}

free((int *)p - 1);//从开辟的起始位置进行释放
}

void FunTest1()
{
Test*p = New(sizeof(Test));
Delete(p);

Test*p1 = NewArray(10);
DeleteArray(p1);
}

int main()
{
FunTest1();
//FunTest();
return 0;
}




接下来,我们再来看一下为什么一定要匹配使用?

#include<iostream>

using namespace std;

class Date
{

private:
int _year;
int _month;
int _day;

};

void FunTest1()
{
int *p1 = new int[5];
int *p2 = new int[5];

int *p3 = new int(2);
int* p4 = new int(3);

delete p1;
delete[]p2;//

delete p3;
delete[]p4;//因为int 为内置类型,所以析构时无需知道数组的大小

}

void FunTest2()
{

Date* p1 = new Date();
Date*p2 = new Date();

Date*p3 = new Date[5];
Date*p4 = new Date[5];

delete p1;
delete[] p2;

delete p3;
delete[] p4;

}
int main()
{
FunTest1();
FunTest2();
return 0;
}


程序执行完,并没有发生错误。



因为对于内置类型和没有显示给出析构函数的类,系统可以直接释放。

那我们显示给出析构函数看一下程序执行结果。从上面的导图饿哦们可以大致了解到,对于非内置类型或无自定义析构函数的类类型来说,析构一段数组空间时,需要知道数组的大小。

#include<iostream>

using namespace std;

class Date
{
public:
/*Date(int year = 0, int month = 0, int days = 0)
:_year(year)
, _month(month)
, _day(days)
{
}*/
~Date()
{
}

private:
int _year;
int _month;
int _day;

};

void FunTest1()
{
int *p1 = new int[5];
int *p2 = new int[5];

int *p3 = new int(2);
int* p4 = new int(3);

delete p1;
delete[]p2;//

delete p3;
delete[]p4;//因为int 为内置类型,所以析构时无需知道数组的大小

}

void FunTest2()
{

Date* p1 = new Date();
Date*p2 = new Date();

Date*p3 = new Date[5];
Date*p4 = new Date[5];

delete p1;
delete[] p2;

delete p3;
delete[] p4;

}
int main()
{
FunTest1();
FunTest2();
return 0;
}




此时。程序就会发生崩溃,这就是我们为什么要配套使用new/delete 与new[]/delete[] 的原因了。

new[]的开辟四个字节空间图:



注:该图来自于:http://blog.csdn.net/hazir/article/details/21413833
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: