C/C++内存管理

C++内存管理方式

通过new和delete操作符进行动态内存管理

申请空间使用 new 在new之后类型即可
new T 申请单个T类型的空间
new T[N] 申请N个T类型的一段连续的空间
int main()
{
    //单个
    int* p1 = new int;
    int* p2 = new int(10);
    //连续
    int* p3 = new int[10];
    int* p4 = new int[10]{ 1,2,3,4,5,6,7,8,9,0 };

    //释放:
    delete p1;
    delete p2;
    //释放连续空间
    delete[] p3;
    delete[] p4;

    return 0;
}

通过监视窗口查看

注意:一定要匹配使用 new/delete new[]/delete[] malloc//free 否则会造成内存泄漏

C++中为什么没有继续使用malloc/free

原因:C++是基于面向对象的程序设计语言,而C语言中的malloc只负责从对象申请空间,并不会调用构造方法对对象进行初始化,free只负责将空间释放掉,在释放时并不会调用析构函数清理对象中的资源。

new:在申请空间之后,也会调用构造方法将空间中的内容初始化好

delete:在释放空间前,也会调用析构函数将对象中的资源清理掉

operator new与operator delete函数

new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。

/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,
尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。
*/
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
 // try to allocate size bytes
 void *p;
 while ((p = malloc(size)) == 0)
 if (_callnewh(size) == 0)
 {
 // report no memory
 // 如果申请内存失败了,这里会抛出bad_alloc 类型异常
 static const std::bad_alloc nomem;
 _RAISE(nomem);
 }
 return (p);
}

而operator delete该函数最终是通过free来释放空间的

new和delete的实现原理

问:先调用函数还是先申请空间? 答:空间

new的使用方式:T* p= new T;

调用void* operator new(size_t size)size要申请空间的总字节数 由operator new负责申请空间。 注意:该方法需要的参数是编译器编译阶段根据new之后的类型确定下来的

1.内置类型

如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是:new/delete申请和 释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申请空间失败时会抛异常, malloc会返回NULL。

2.自定义类型

new的原理 1. 调用operator new函数申请空间 2. 在申请的空间上执行构造函数,完成对象的构造 delete的原理 1. 在空间上执行析构函数,完成对象中资源的清理工作 2. 调用operator delete函数释放对象的空间 new T[N]的原理 1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申 请 2. 在申请的空间上执行N次构造函数 delete[]的原理 1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理 2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

注:构造函数不负责给对象开辟空间,只负责将空间中的成员初始化成功

new操作符 和 操作符new的区别:

new操作符

操作符new

指的是用来申请空间的new关键字

new即是关键字(所以使用时不需要包含任何头文件),new也是一个C++中的操作符,即:new是可以重载的

是一个函数

void* operator new(size_t size)

定位new表达式(placement-new)

定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。 使用格式: new (place_address) type或者new (place_address) type(initializer-list) place_address必须是一个指针,initializer-list是类型的初始化列表 。

问:为什么C++中使用了new/new[]还要使用malloc?

原因:在C++中申请空间的时候,使用的都是new或者new[],但是在特殊情况下还需使用malloc,比如实现一个内存池(一大块内存空间)。

注:malloc申请的空间肯定要比用户需要的空间大,因为还要对申请的空间进行管理

malloc实际申请的空间是 _CrtMenBlockHeader结构体的大小+用户所申请的大小+4个字节(防止越界)

为什么要实现内存池?

当用户需要申请空间的时候,不需要再去malloc了,直接从内存池中获取就可以了

只要能从该空间上执行构造方法,该块空间才可以变成完整的对象

class Date
{
public:
    Date(int year = 1900, int month = 1, int day = 1)
        :_year(year)
        , _month(month)
        , _day(day)
    {
        cout << "Date(int,int,int)" << endl;
    }
    ~Date()
    {
        cout << "~Date()" << endl;
    }
private:
    int _year;
    int _month;
    int _day;
};
Date* New(size_t size)
{
    //申请内存空间
    Date* pd = (Date*)malloc(sizeof(Date));

    //指向构造方法
    new(pd) Date();

    return pd;
}
void Delete(Date* pd)
{
    if (pd)
    {
        //调用析构函数清理对象中的资源
        pd->~Date();

        //调用free释放内存空间
        free(pd);
    }
}
int main()
{
    //pd指向的堆空间并不是对象,因为malloc在申请空间的时候,不会调用构造方法
    //而是和对象大小相同的一块内存空间
    Date* pd = (Date*)malloc(sizeof(Date));

    //如果可以在pd指向的空间上执行构造方法,就可以将pd指向的空间变为对象
    new(pd) Date(2023,1,12);

    delete pd;

    pd = New(sizeof(Date));

    Delete(pd);

    return 0;
}

总结:定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义 类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值