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

来源:互联网 发布:网络安全工程师职责 编辑:程序博客网 时间:2024/05/21 09:16

动态内存管理核心:
这里写图片描述
首先,我们来重载一下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 newvoid 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

1 0
原创粉丝点击