• C++动态内存管理之深入探究new和delete


     C++中程序存储空间除栈空间和静态区外,每个程序还拥有一个内存池,这部分内存被称为自由空间(free store)或堆(heap)。程序用堆来存储动态分配的对象,即,那些程序运行时分配的对象。动态对象的生存期由程序来控制 ,当动态对象不再使用时,程序必须显式的销毁它们。

    new和delete的使用

        C++中通过一对运算符new和delete来完成动态内存分配。new,在动态内存中为对象分配空间并返回一个指向该对象的指针,我们可以选择对对象初始化;delete接受一个动态对象的指针,销毁对象,并释放对应内存。使用示例如下:

     

    复制代码
     1 void Test()
     2 {
     3     int *pi1 = new int;           
     4 //pi1指向一个动态分配的4个字节(int型)、未初始化的无名对象;*pi1的值未定义
     5     int *pi2 = new int(2);        
     6 //pi2指向的对象的值是2,动态分配4个字节( 1个 int) 的空间并初始化为2
     7     int *pi3 = new int[3];        //动态分配12个字节( 3个 int) 的空间
     8     int *pi4 = new int();         //值初始化为0;*pi4为0
     9 
    10     delete pi1;
    11     delete pi2;
    12     delete [] pi3;
    13     delete pi4;
    14 }
    复制代码

         自由空间分配的内存是无名的,new无法为其分配的对象命名,而是返回一个指向该对象的指针。默认情况下,动态分配的对象是默认初始化的,即内置类型或组合类型的对象的值是未定义的,类类型的对象将用默认构造函数进行初始化。
        new和delete、 new[] 和delete[] 一定匹配使用 , 一定匹配使用 , 一定匹配使用 ! ! ! 重要的事说三遍! 否则可能出现内存泄露甚至崩溃的问题。
    深入探究new和delete、 new[] 和delete[]内部

    通过下面这段代码我们来详细比较一下new和delete、 new[] 和delete[]内部实现

    复制代码
     1 class Array
     2 {
     3     public :
     4     Array(size_t size = 10)//构造函数
     5         : _size(size)
     6         , _a(0)
     7     {
     8         cout << "Array(size_t size) " << endl;
     9         if (_size > 0)
    10         {
    11             _a = new int[size];
    12         }
    13     }
    14     ~Array()             //析构函数
    15     {
    16         cout << "~Array() " << endl;
    17         if (_a)
    18         {
    19             delete[] _a;
    20             _a = 0;
    21             _size = 0;
    22         }
    23     }
    24 private:
    25     int*_a;
    26     size_t _size;
    27 };
    28 void Test()
    29 {
    30     Array* p1 = (Array*)malloc(sizeof(Array));
    31     Array* p2 = new Array;
    32     Array* p3 = new Array(20);
    33     Array* p4 = new Array[10];
    34     free(p1);
    35     delete p2;
    36     delete p3;
    37     delete[] p4;
    38 }
    39 int main()
    40 {
    41     Test();
    42     getchar();
    43     return 0;
    44 }
    复制代码

    转到反汇编可以看到,在call指令处调用了operator new:

    转到定义处可以看到operator new 的具体原型:

    再按F10程序来到了析构函数

    执行完之后,输出

    此时new已经完成了申请空间的任务,然后调用构造函数创建对象。同样,detele的定义如下

     

    delete先调用析构函数清除对象。然后调用operator detele释放空间。

    Array* p4 = new Array[10];
    delete[] p4;

        执行这两条语句的时候实际上调用operator new[](10*sizeof(Array)+4)分配大小为10*sizeof(Array)+4空间,其中多的四个字节空间用于存放N(10)这个数字以便于delete中调用析构函数析构对象(调用析构函数的次数),空间申请好了之后调用构造函数创建对象。delete[] p4执行的时候首先取N(10)对象个数,然后调用析构函数析构对象,最后用operator delete[]函数释放空间。

    总结:
    1. operator new/operator delete operator new[] /operator delete[] 和 malloc/free用法一 样。
    2. 他们只 负责分配空间/释放空间, 不会调用对象构造函数/析构函数来初始化/清理对象。
    3. 实际operator new和operator delete只是malloc和free的一层封装。

    【 new作用】 调用operator new分配空间。 调用构造函数初始化对象。

    【 delete作用】 调用析构函数清理对象 调用operator delete释放空间

    【 new[] 作用】 调用operator new分配空间。 调用N次构造函数分别初始化每个对象。

    【 delete[] 作用】 调用N次析构函数清理对象。  调用operator delete释放空间。

  • 相关阅读:
    微软首届Power Platform开发黑客松大赛
    PowerApps 简介
    PowerBI KPI 演示
    什么是Power Platform低代码
    利用Microsoft PowerApps模板,一分钟创建Service Desk服务程序
    Power Platform
    Microsoft Power Platform 低代码开发平台
    登录监听Enter键
    代理配置
    Enjoy the pain about Moloch
  • 原文地址:https://www.cnblogs.com/tangshiguang/p/6735401.html
Copyright © 2020-2023  润新知