C++动态内存管理

本文详细探讨了C++中的动态内存管理,包括C语言中的malloc/free,C++中的new/delete、new[]/delete[],以及它们与malloc/free的区别。特别强调了new/delete在调用构造和析构函数方面的特性,以及new[]在处理类对象数组时的额外步骤。

1.C语言动态内存管理

在C语言中,我们主要对内存的动态管理主要使用的是malloc和free两个C标准库函数,所以我们主要来介绍一下malloc/free

  • malloc

    1. malloc函数原型

      void* __cdecl malloc(size_t _Size);
    2. malloc 不保证成功 要检测return

    3. malloc首先会扫描之前由free()所释放的空闲内存块列表,以求找到尺寸大于或等于要求的一块空闲内存。如果这一内存块的尺寸正好与要求相当,就将它返回给调用者,如果是一块较大的内存,那么将对其进行分割,在将一块大小相当的内存返回给调用者的同时,把较小的那块空闲内存块保留在空闲列表中。

    4. malloc需要分配的内存会比实际的size多36byte

    5. mallco如果分配失败,则返回一个空指针(NULL)

    6. 当不需要再使用申请的内存时,记得释放

    7. malloc不会调用构造函数函数

  • free

    1. free是将之前用malloc分配的空间还给程序或者是操作系统

    2. free不会调用析构函数

    3. 不能free所申请空间的一部分

    4. 所申请的空间只能free一次,如果free两次以上会出错。(释放空指针例外,释放空指针其实也等于啥也没做,所以释放空指针释放多少次都没有问题)

    5. free()释放的是指针指向的内存!注意!释放的是内存,不是指针!指针并没有被释放,指针仍然指向原来的存储空间。


2.在C++中使用C库函数申请内存什么情况下会出问题?

  1. 在使用malloc对一个含有析构函数的类申请空间,且用delete[]来释放是,程序会出现崩溃

  2. 在使用new[]对一个含有析构函数的类申请空间是,用free释放,程序会出现崩溃


3. C++是如何进行动态内存申请的?

C语言内存管理方式在C++中可以继续使用,同时C++又提出了自己的内存管理方式:C++中通过newdelete运算符进行动态内存管理。

在使用关键字new后会先申请空间,在调用构造函数,在使用delete时,会先调用构造函数,在释放空间。

而关键字new delete在底层会调用自己的重定义函数operator new()operator delete(),而在重定义newdelete中,还是会调用mallocfree,因此newdelete是对mallocfree的封装,并且在一定程度上比mallocfree安全。

因此,一般情况下使用 newdelete进行内存申请。


4. 剖析new、delete、new[]、delete[]的原理

  • new

    1. new是一个关键字

    2. new不会出错,不需要检验返回值,即不需要判空

    3. new在底层调用了 void* operator new(size_t size),而operator在底层有调用了malloc,原型如下:

      void* operator new(size_t nSize)
      {
         return malloc(nSize);
      }
    4. 整个调用过程为:
      new -> 计算字节数->operator new(字节数) -> malloc(字节数)->构造函数

    5. new会自动计算字节数

    6. new先申请空间,在调用构造函数。

  • delete

    1. delete是一个关键字

    2. delete在底层调用了operator delete(), operator delete()调用了free,原型如下:

      void operator delete(void* p)
      {
         free(p);
      }
    3. delete的整个调用过程如下

      delete -> 调用析构函数,清理对象中的资源-> dperator delete(p) -> free(p)

    4. delete会自动调用析构函数

    5. delete先调用析构函数,在释放空间

  • new[]

    1. new[]在底层调用了 operator new[];

    2. new[]整体的调用过程如下:(test为一个类)

      new test[N]-> operator new[](sizeof(test)*N + 4)->operator new(size) -> malloc(size) ->用N次构造函数

    3. new[]会比new多申请4个字节的空间,用来存放申请空间的个数N

    4. 将对象个数填写到空间的前4个字节后,将空间的首地址向后偏移4个字节

    5. 同样的new[],会自动的计算空间大小

  • delete[]

    1. 从对象前4个字节取析构函数的调用次数N

    2. 调用N次析构函数 — 完创建的对象早释放

    3. delete[]在底层调用了operator delete函数

    4. delete[]整体的调用过程:

      delete[]->向前偏移4字节,取到N -> 调用N构造函数->operator delete[] -> operator delete -> free

  • 但存在析构函数时,new[] 会对申请4个字节,且向后偏移4个字节,delete[]会向前偏移4个字节

因此使用delete或者free会崩溃(不会向前偏移,只释放部分空间)


5. new/delete、new[]/delete[]、 malloc/free之间的区别

  • new/delete 和 malloc/free之间的区别

    1. new能够自动计算需要分配的内存空间,而malloc需要手工计算字节数。例如,int* p1=new int[2] , int* p2=malloc(2*sizeof(int))。

    2. new/delete直接带具体类型的指针,malloc/free返回void类型的指针。

    3. new是类型安全的,而malloc不是。例如,int* p=new float[2],编译时就会报错;而int* p=malloc(2*sizeof(float)),编译时编译器就无法指出错误来。

    4. new一般由两步构成,分别是new操作和构造。new操作对应于malloc,但new操作可以重载,可以自定义内存分配策略,不做内存分配,甚至分配到费内存设备上,而malloc不可以。

    5. new将调用构造函数,而malloc不能;delete将调用析构函数,而free不能。

    6. malloc/free需要库文件stdlib.h支持,new/delete则不需要库文件支持。

  • new[]/delete[] 和 new/delete的区别

    1. 类存在显示析构函数时,会多开辟4个字节的空间

    2. new[] 对多次调用构造函数。

    3. delete会多次调用析构函数

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值