C和C++中的动态内存管理

C中的动态内存管理

1、C语言中使用malloc/calloc/realloc/free进行动态内存管理,malloc/calloc/realloc用来在堆上开辟空间,free将申请的空间释放掉。
1)malloc
原型:void * malloc(size_t size);
该函数将在堆上分配一个size byte大小的内存。它分配的单原完全按字节大小计算,因此如此分配N个单原的student_t,那么要这样实现:(stdent_t )malloc(N sizeof (student_t)); (可用memset初始化)
2)calloc
原型:void* calloc(size_t size, int count);
该函数解决了上面的函数的不足,它将分配count个size大小的单原,因此在便用此函数的时候就会很方便,比如对上面的例子就可以:(student_t *)calloc(sizeof(t_student), N)就可以了。这样使用就会很清晰的知道分配的内存是一种什么样的逻辑方式。(会将申请的内存空间初始化)
3)realloc
改变原有内存空间的大小,若不能改变,则会开辟一段新的内存,将原有内存的内容拷贝过去,不会对新开辟的空间进行初始化。
4)_alloc
使用_alloc在栈上动态开辟内存,栈上空间具有函数作用域,在函数结束后系统自动回收,不用用户管理。

注意:堆上的内存需要用户自己管理,也就是说用户动态malloc/calloc/realloc的空间,必须自己free掉,否则会造成内存泄漏。
2、常见的内存泄漏

void MemoryLeaks()
{
    //1.内存申了忘记释放
    int *pTest = (int *)malloc(10*sizeof(int));
    assert(NULL != pTest);
    Do();

    //2.程序逻辑不清,以为释放了,实际内存泄漏
    int *pTest1 = (int *)malloc(10*sizeof(int));
    int *pTest2 = (int *)malloc(10*sizeof(int));
    Do();
    pTest1 = pTesr2;
    free(pTest1);
    free(pTest2);

    //3.程序误操作,将堆破坏
    char *pTest3 = (char *)malloc(5);
    strcpy(pTest3,"Memory Leaks!");
    free(pTest3);

    //4.释放是传入的地址和申请时的地方不同
    int *pTest4 = (int *)malloc(10*sizeof(int));
    assert(NULL != pTest4);
    pTest4[0] = 0;
    pTest4++;
    Do();
    free(pTest4);
}

C++中的动态内存管理

1、C++中使用new和delete运算符进行动态内存管理。
【new作用】
调用operator new分配空间。
调用构造函数初始化对象。
【delete作用】
调用析构函数清理对象
调用operator delete释放空间
【new[]作用】
调用operator new分配空间。
调用N次构造函数分别初始化每个对象。
【delete[]作用】
调用N次析构函数清理对象。(N是new[ ]出来的)
调用operator delete释放空间

这里写图片描述

这里写图片描述
2、C++的其他内存管理接口(placement版本)
void * operator new (size_t size);
void operator delete (size_t size);
void * operator new [](size_t size);
void operator delete[] (size_t size);
1) operator new/operator delete operator new[]/operator delete[] 和 malloc/free用法一
样。
2)他们只负责分配空间/释放空间,不会调用对象构造函数/析构函数来初始化/清理对象。
3)实际operator new和operator delete只是malloc和free的一层封装。

void Test()
{
int *p1 = new int; //动态分配4个字节(1个int)的空间单个数据
int *p2 = new int(2); //动态分配4个字节(1个int)的空间并初始化为2
int *p3 = new int[2]; //动态分配8个字节(2个int)的空间
delete p1;
delete p2;
delete[] p3;
}

注意:new和delete、new[ ]和delete[ ]要匹配使用,否则会造成内存泄漏甚至崩溃的问题。
栈:
非静态局部变量/函数参数/返回值等等,栈是向下增长的。
数据段:
存储全局数据和静态数据(包括局部静态变量)
堆:
程序运行时的动态内存分配,可以向上增长的。
代码段:
可执行的代码和只读常量。
3、malloc/free和new/delete的区别和联系
1)都是动态内存管理的入口。
2)malloc/free是C/C++的标准库函数,而new/delete是C++的操作符
3)malloc/free只是动态的分配内存空间/释放空间。而new/delete除了分配空间还会调用构造函数和析构函数
4)malloc/free需要手动计算类型大小且返回值为void*,new/delete可以自己计算类型的大小,返回对应类型的指针。

    class Array
    {
    public:
    Array(size_t size = 10)
        :_size(size)
        , _a(0)
    {
        cout << "Array(size_t size)" << endl;
        if (size > 0)
    {
            _a = new int[size];
        }
    }
    ~Array()
    {
        cout << "~Array()" << endl;
        if (_a)
        {
            delete[]_a;
            _a = 0;
            _size = 0;
        }
    }
    private:
    int* _a;
    size_t _size;
    };

    void Test()
    {
                //malloc/free函数只是动态的分配内存空间/释放空间。
    Array* p1 = (Array*)malloc(sizeof(Array));
                //new/delete操作符除了分配空间还会调用构造函数和析构函数来初始化和清理。
    Array* p2 = new Array;    //1个类类型
    Array* p3 = new Array(20);    //1个类类型并初始化为20
    Array* p4 = new Array[10];    //10个类类型
    free(p1);
    delete p2;
    delete p3;
    delete[] p4;
    }
    int main()
    {
    Test();
    //程序结果构造函数和析构函数被调用12次。
    return 0;
    }

4、定位new表达式
定位new表达式是在以分配的原始空间中调用构造函数初始化一个对象。
new(place_address) type;
new(place_address) type(initializer-list);
place_address必须是一个指针,initializer-list是初始化列表。
eg:
利用mallco/free和定位new表达式来模拟new/delete和new[]/delete[]:

    class A
    {
    public:
    A(int a = 2)
        :_a(a)
    {
        cout << "A()" << endl;
    }
    void Print()
    {
        cout << _a << endl;
    }
    ~A()
    {
        cout << "~A()" << endl;
    }

    private:
    int _a;
    };

    int main()
    {
    //分配1个A类型空间
    A* pa = (A*)malloc(sizeof(A));  
    new(pa)A(1);                    //调用构造函数
    pa->~A();                      //调用析构函数
    free(pa);
    cout << endl;
    //分配5个A类型的空间
    A* pa1 = (A*)malloc(5 * sizeof(A));
    for (int i = 0; i < 5; i++)
    {
        new(pa1 + i)A(i);           //调用5次构造函数
    }
    for (int i = 0; i < 5; i++)
    {
        (pa1+i)->~A();              //调用5次析构函数
    }
    free(pa1);
    return 0;
    }

结果如下:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值