美文网首页
C++ 内存操作new & delete

C++ 内存操作new & delete

作者: 我阿郑 | 来源:发表于2021-12-21 09:48 被阅读0次

    一、new & delete

    回顾malloc/freemalloc申请而来的只是内存,严格地说并不是“对象”

    // 4个int , 16个字节
    int* p = (int*) malloc(16);
    for(int i=0; i<4; i++){
        p[i] = i;
    }
    free(p);
    

    在C++中,用new/delete操作符取代malloc/free

    // 申请一个对象 :
    int*  p = new int; 
    delete  p; // 释放
    
    // 申请多个对象 :例如,申请1024个int对象
    int*  p = new int [1024] ;
    delete []  p;
    
    // 申请一个int, 一个double
    
    int* p1 = new int;
    *p1 = 12;
    delete p1; // 用完后释放 
    
    double p2 = new double(12.34);
    printf("%f \n", *p2);
    delete p2; // 用完后释放
    
    // 申请一个Student对象
    Student* s = new Student;
    s->id = 12;
    strcpy(s->name, "shaofa");
    // 用完之后,释放
    delete s;
    
    //申请一个长度为10000的char数组,填充为1,2,3,...
    char*  arr = new char [10000];
    for(int i=0; i<10000; i++)
    {
        arr[i] = i + 1;
    }
    delete [] arr;
    
    

    注意:

    • new的返回值直接就是对象指针,不用再转换
    • new的时候可以设初始值 new int(12);
    • 用new申请的内存,必须用delete释放
    • 如果new的时候用了[],则释放的时候使用delete []操作符

    和free一样,delete之后指针所指向的内存不再可用

    delete p;
    p = nullptr; // 最好置为空指针
    

    动态创建对象

    对于class类型,必须用new/delete来创建、销毁。
    malloc/free是无法胜任的

    new:动态创建一个对象:

    • 申请一块内存
    • 内部调用了构造函数

    delete:释放这个对象:

    • 调用了析构函数
    • 释放内存
    // 动态创建一个对象
    // new的时候构造函数被调用,delete的时候析构函数被调用
    Circle* c = new Circle(); // 默认构造函数
    Circle* c = new Circle; // 不加括号也可以
    Circle* c = new Circle(1,1,4); // 传构造参数
    delete c;
    
    
    // 动态创建多个对象
    // ⚠️ 含有“默认构造函数”的类,才可能使用new []一次性地创建多个对象
    Circle* c = new Circle[4];
    delete [] c;
    
    

    new与malloc的最大区别

    new和malloc巨大区别:

    • malloc返回的只是一片内存、不是对象(malloc不负责构造)
    • new返回的是一个可以正常工作的对象(因为它调用了构造函数)

    所以,new/delete 不仅仅时申请内存这么简单,它是申请了内存,并且构造了对象

    Circle* p = (Circle*)malloc(sizeof(Circle));
    // 强转为Circle* ??? 没用,因为没有调用构造函数
    
    double area = p->GetArea(); // !!! 对象不可用
    

    小结

    • new得到的是一个对象,malloc得到的不是对象 。因此,C++的类必须用new,不能用malloc

    • new一个对象的时候,可以传参,内部会调用构造函数。

    • new多个对象(数组)的时候,不能传参数,要求该类必须有默认构造函数

    二、用new创建类对象与不用new的区别

    • new创建类对象需要指针接收
    • new创建类对象使用完需delete销毁
    • new创建对象直接使用堆空间,而局部不用new定义类对象则使用栈空间
    • new对象指针用途广泛,比如作为函数返回值、函数参数等
    • 频繁调用场合并不适合new,就像new申请和释放内存一样
    // 1. 使用new创建对象
    // new申请的对象,则只有调用到delete时再会执行析构函数,如果程序退出而没有执行delete则会造成内存泄漏
    CTest* pTest = new CTest();
    delete pTest;
    
    // 2. 不使用new,直接使用类定义声明
    // 此种创建方式,使用完后不需要手动释放,该类析构函数会自动执行
    CTest mTest;
    
    // 例如:
    #include <iostream>
    using namespace std;
     
    class A
    {
    private:
        int n;
    public:
        A(int m):n(m)
        {
        }
        ~A(){}
    };
     
    int main()
    {
        A a(1);  //栈中分配
        A b = A(1);  //栈中分配
        A* c = new A(1);  //堆中分配
       delete c;
        return 0;
    }
    

    第一个隐式调用,第二个显式调用,两者都是在进程虚拟地址空间中的栈中分配内存,而第三种使用了new,在堆中分配了内存,栈中内存的分配和释放是由系统管理,堆中内存的分配和释放必须由程序员手动释放

    总结

    一般来说对于一个进程栈的大小远远小于堆的大小。
    在Window下,栈的大小是2MB,Linux下,默认栈空间大小为8MB。对于堆,比如32位系统最大不超过2G,而64位系统最大不超过4G,当需要分配一个非常大的内存时,请用new
    栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。
    堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在 堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就需要申请足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。
    由上可知,一般情况不使用new,直接使用类定义声明,申请内存特别大的情况下,或者作为函数返回值时,使用new创建对象

    相关文章

      网友评论

          本文标题:C++ 内存操作new & delete

          本文链接:https://www.haomeiwen.com/subject/nzotqrtx.html