动态内存管理

1.总结并剖析malloc/free和new/delete之间关系和差异

malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。malloc/free需要手动计算类型大小且返回值会void*,new/delete可自己计算类型的大小,返回对应类型的指针。

对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。

因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。

我们先看一看malloc/free和new/delete如何实现对象的动态内存管理,见下面示例。

#include<iostream>
using namespace std;
class AA
{
public:
    AA()
    {
        cout << "构造函数" <<"AA()" << endl;
    }
    ~AA()
    { 
        cout << "析构函数" <<"~AA()" << endl; 
    }
    void Initialize(void)
    { 
        cout << "模拟构造" << endl; 
    }
    void Destroy(void)
    { 
        cout << "模拟析构" << endl;
    }
};

void UseMallocFree(void)
{
    AA  *a = (AA *)malloc(sizeof(AA));   // 申请动态内存
    a->Initialize();                        // 初始化
    //…
    a->Destroy();   // 清除工作
    free(a);        // 释放内存
}

void UseNewDelete(void)
{
    AA  *a = new AA;  // 申请动态内存并且初始化
    //…
    delete a;           // 清除并且释放内存
}

类Obj的函数Initialize模拟了构造函数的功能,函数Destroy模拟了析构函数的功能。函数UseMallocFree中,由于malloc/free不能执行构造函数与析构函数,必须调用成员函数Initialize和Destroy来完成初始化与清除工作。函数UseNewDelete则简单得多。

所以我们不要企图用malloc/free来完成动态对象的内存管理,应该用new/delete。由于内部数据类型的“对象”没有构造与析构的过程,对它们而言malloc/free和new/delete是等价的。

既然new/delete的功能完全覆盖了malloc/free,为什么C++不把malloc/free淘汰出局呢?这是因为C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存。
如果用free释放“new创建的动态对象”,那么该对象因无法执行析构函数而可能导致程序出错。如果用delete释放“malloc申请的动态内存”,理论上讲程序不会出错,但是该程序的可读性很差。所以new/delete必须配对使用,malloc/free也一样。

2.剖析new/delete、new[ ]/delete[ ]

注意:
C++的其他内存管理接口
void * operator new (size_tsize);
void operator delete (size_tsize);
void * operator new ;
void operator delete[] (size_tsize);
总结:
1. operator new/operator delete
operator new[]/operator delete[] 和malloc/free用法一样。
2. 他们只负责分配空间/释放空间,不会调用对象构造函数/析构函数来初始化/清理对象。
3. 实际operator new和operator delete只是malloc和free的一层封装,
不是重载 new 和 delete 表达式。

new/delete
new/delete动态管理对象。
new在申请动态内存时会调用operator new分配空间,调用构造函数完成初始化,delete在释放动态内存时会调用析构函数完成清理工作,调用operator delete释放空间,UseNewDelete()测试用例:

int main()
{
    UseNewDelete();
    system("pause");
}

这里写图片描述

new[ ]/delete[ ]
new[]/delete[]动态管理对象数组。
new[N]
1. 调用operator new分配空间。
2. 调用N次构造函数分别初始化每个对象。
delete[]
1. 调用N次析构函数清理对象。(思考这里怎么N是怎么来的?)
2. 调用operator delete释放空间。

这里写图片描述

实现NEW_ ARRAY/DELETE_ARRAY宏,模拟new[]/delete[]申请和释放数组

实现NEW_ ARRAY/DELETE_ARRAY宏,模拟new[]/delete[]申请和释放数组,来看看这两个运算符到底做了些什么事情:

#define NEW_ARRAY(PTR, TYPE, N)                             /
        do{                                                 /
            PTR = (TYPE*)operator new(sizeof(TYPE)*N + 4);  /
        (*(int*)PTR) = N;PTR = (TYPE*)((char*)PTR + 4);     /
        for (size_t i = 0; i < N; i++)                      /
            new(PTR+i)TYPE;                                 /
    } while (false);                                    

#define DELETE_ARRAY(PTR, TYPE)                         /
    do{                                                 /
        int N = *((int*)PTR-1);                         /
    for (size_t i = 0; i < N; i++)                      /
            PTR[i].~TYPE();                                /
    PTR = (TYPE*)((char*)PTR - 4);                      /
    operator delete(PTR);                               /
    } while (false);

补充:
1.new(PTR+i)TYPE;
定位new表达式(replacement版本)
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。
new (place_address) type
new (place_address) type(initializer-list)
place_address必须是一个指针,initializer-list是类型的初始化列表。
2.do{
}while(false) 是为了生成一个局部域,定义和使用临时变量,避免变量重定义。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值