首页 > 编程语言 >C++中,new与malloc的区别何在?(代码实验向)

C++中,new与malloc的区别何在?(代码实验向)

时间:2024-01-21 15:00:57浏览次数:34  
标签:10 malloc C++ Calling new Rect delete

在C++中,new与malloc()都可用于在堆中分配一块内存。其中,new是C++的语法,而malloc则来自古老的C语言,二者在使用时有何区别?

new会调用构造函数,而malloc()不会

假设有一个矩形类Rect,定义如下:

class Rect {
public:
    Rect() {
        /* 初始化矩形的宽和高为10 */
        mWidth = mHeight = 10;
        std::cout << "Calling Rect(): ";
        display();
    }

    Rect(float width, float height) {
        /* 指定矩形的宽和高,构造一个矩形 */
        mWidth = width;
        mHeight = height;

        std::cout << "Calling Rect(float, float): ";
        display();
    }

    ~Rect() {
        /* 析构函数 */
        std::cout << "Calling ~Rect(): ";
        display();
    }

    void display() {
        /* 输出矩形信息,最后会额外输出一个换行符 */
        std::cout << "Rect(" << mWidth << ", " << mHeight << ")\n";
    }

private:
    float mWidth;  // 矩形的宽
    float mHeight;  // 矩形的高
};

这个类的实现很简单,唯一需要注意的地方在于构造函数和析构函数内都有一条输出,便于我们了解程序是否调用了相关函数。

我们的测试代码长这个样子:

int main() {
    std::cout << "[INFO] malloc:\n";
    auto ptrRect1 = (Rect*)malloc(sizeof(Rect));
    ptrRect1->display();

    std::cout << "\n[INFO] new:\n";
    auto ptrRect2 = new Rect;
    ptrRect2->display();

    std::cout << "\n[INFO] program finish:\n";
}

编译运行后,程序的输出如下:

[INFO] malloc:
Rect(9.86058e+27, 6.30584e-43)

[INFO] new:
Calling Rect(): Rect(10, 10)
Rect(10, 10)

[INFO] program finish:

可以看到,调用malloc后,没有对分配的那块内存初始化,最后输出矩形的宽和高是内存中保存的随机值;而使用new分配的对象会调用构造函数初始化内存,这就是二者的区别所在。

另外还有一点,这两块在堆上分配的内存没有被回收,虽然在这个小程序中,程序运行结束后会由操作系统负责回收内存,但作为一名专业的编程人员,回收不必要的内存总是一个好习惯,而这,就需要我们考虑delete与free()的区别。

delete会调用析构函数,而free()不会

想必大家都已经猜到了,与new/malloc()的区别类似,delete相较于free, 会调用析构函数。

int main() {
    auto ptrRect1 = (Rect*)malloc(sizeof(Rect));
    auto ptrRect2 = new Rect;

    std::cout << "[INFO] free:\n";
    free(ptrRect1);

    std::cout << "\n[INFO] delete:\n";
    delete ptrRect2;

    std::cout << "\n[INFO] program finish:\n";
}

程序的输出如下所示:

Calling Rect(): Rect(10, 10)
[INFO] free:

[INFO] delete:
Calling ~Rect(): Rect(10, 10)

[INFO] program finish:

输出结果验证了我们的说法。

对象数组的分配与释放

我们已经知道,malloc/free作为C语言的底层API, 不会为我们做额外的工作,而C++中的new/delete同时承担构造/析构的工作。最后还留有一个问题,对于对象的数组,也遵循相同的规定吗?答案是肯定的,请看下面这个例子:

int main() {
    std::cout << "[INFO] create 5 rects:\n";
    auto rect_array = new Rect[5];
    
    std::cout << "\n[INFO] delete rect array:\n";
    delete[] rect_array;
}

输出为:

[INFO] create 5 rects:
Calling Rect(): Rect(10, 10)
Calling Rect(): Rect(10, 10)
Calling Rect(): Rect(10, 10)
Calling Rect(): Rect(10, 10)
Calling Rect(): Rect(10, 10)

[INFO] delete rect array:
Calling ~Rect(): Rect(10, 10)
Calling ~Rect(): Rect(10, 10)
Calling ~Rect(): Rect(10, 10)
Calling ~Rect(): Rect(10, 10)
Calling ~Rect(): Rect(10, 10)

从输出中可以看到,使用new Rect[5]分配5个Rect对象时,会为5个Rect对象分别调用一次构造函数;而使用delete[]释放内存时,也会同时调用Rect对象的析构函数。

有的朋友可能好奇:如果不使用delete[] rect_array, 直接使用delete rect_array, 会发生什么呢?既然写到这里,就顺便试一试吧:

int main() {
    std::cout << "[INFO] create 5 rects:\n";
    auto rect_array = new Rect[5];
    
    std::cout << "\n[INFO] delete rect array:\n";
    delete rect_array;
}

我使用的clang编译器给了我一个Warning: 使用new[]分配的内存需要使用delete[]释放。但是编译能通过,最后的输出结果为:

[INFO] create 5 rects:
Calling Rect(): Rect(10, 10)
Calling Rect(): Rect(10, 10)
Calling Rect(): Rect(10, 10)
Calling Rect(): Rect(10, 10)
Calling Rect(): Rect(10, 10)

[INFO] delete rect array:
Calling ~Rect(): Rect(10, 10)

因此,将delete[]换成delete后,只有第一个Rect对象被释放,程序的状态也出现了异常。

结语

最后和大家讲个笑话:我最早学C语言的时候,以为使用malloc()申请的内存如果没有使用free()释放,这块内存就再也不能用了。所以,最早学的时候,不敢使用malloc()这个函数,总是感觉自己电脑的内存越来越小。后来才知道,原来操作系统会在程序运行结束后回收内存,所以完全不必担心,尽管放心大胆地写,没有听说谁写代码把电脑干废的。

在新一代的C++中,有智能指针这一更为高级的概念,不过这些都是后话了,有时间再写吧。

标签:10,malloc,C++,Calling,new,Rect,delete
From: https://www.cnblogs.com/overxus/p/17977804

相关文章

  • Verdi信号平移+研发管理体系+malloc和calloc函数区别+使用__FILE__只打印文件名+使用i
    Verdi信号平移信号左移是将光标移动在双引号以内的信号名左边,然后先输入数字,可以带上单位,如[ns|n]、[ps|p],然后按<<-按键。https://blog.csdn.net/qq_40268672/article/details/132915499信号右移信号右移是数字在右边,信号在左边,用右移符号,其它不变。研发管理体系https://......
  • 24new和delete的运算符重载视角
    new和delete的运算符重载视角new和malloc对比:malloc按字节开辟内存,返回void*,需要强制类型转换;new开辟内存需要指定类型new在malloc的基础上,还会进行数据的初始化malloc开辟内存失败返回nullptr,new抛出bad_alloc类型的异常delete和free对比:delete是在free的基础上进行了析......
  • 25new和delete重载实现的对象池应用
    new和delete重载实现的对象池应用在类底层维护一个结构体链表,new和delete重载以避免大量重复的new和delete操作。usingnamespacestd;#include<iostream>staticconstintPOOL_ITEM_SIZE=1000000;template<typenameT>classQueue{public: Queue() { _front=_r......
  • 【C++入门到精通】C++入门 —— 引用、内联函数
     目录一、引用1.引用的概念2.引用的特性3.常引用4.引用的使用场景        ⭕做参数        ⭕做返回值5.传值、传引用效率比较值和引用的作为返回值类型的性能比较6.引用和指针的区别 引用和指针的不同点 二、内联函数1.内联函数的概念2.内联函数的特性3.宏与内......
  • C++多重返回值:引用参数、结构体和元组实例详解
     在C++中,函数通常只能返回一个值。但是,可以通过引用参数、结构体、元组(C++11及以后版本支持)等方式实现函数具有多个返回值的效果。以下是其中几种方法的实例:1.通过引用参数:#include<iostream>//通过引用参数实现多个返回值voidmultipleReturns(inta,intb,int&......
  • 20C++的运算符重载
    C++的运算符重载编译器在做对象运算的时候,会调用对象的运算符重载函数(优先调用成员方法)。如果找不到合适的成员方法,则在全局作用域寻找合适的运算符重载函数.#include<iostream>usingnamespacestd;//复数类classCComplex{private: intmreal; intmimage; //友元函......
  • C++多线程3
    1利用栈特性自动释放锁RAII1.1什么是RAIIRAII(ResourceAcquisitionIsInitialization),使用局部对象管理资源的技术称为资源获取既初始化,它的生命周期由操作系统管理,无需人工干预。为什么要引入自动释放锁,因为我们有时会因为忘记释放锁,而造成死锁或内存泄漏。我们先来手动实......
  • c++函数模板
    一.模板概念:就是建立通用的摸具,大大提高复用性特点:模板不可以直接使用,它只是一个框架模板的通用并不是万能的c++提供两种模板机制函数模板和类模板二.函数模板作用:建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表作用:建立一个通用函数......
  • 初中英语优秀范文100篇-064WeChat,a New Way of Life-微信,一种新的生活方式
    PDF格式公众号回复关键字:SHCZFW064记忆树1Inmyopinion,usingWeChattochatisanewwayoflife.翻译在我看来,使用微信聊天是一种新的生活方式。简化记忆微信句子结构Inmyopinion介绍性短语,用于表达作者的观点主语:"usingWeChattochat"(使用微信聊天)......
  • C++U3-第11课-单、双链表
    学习目标 链表概念计算机存储结构 单链表 实现单链表       删除 插入节点  双向链表  实现双链表         [【数据结构-链表】猴子选大王] 【题意分析】通过循环报数的方式每一次剔除......