当前位置: 首页 > news >正文

new与malloc区别

前言动态分配内存,我们经常用到的是newmalloc,很多童鞋没有搞清楚这俩的本质区别,导致了代码产生了一些非预期现象。今天跟大家一起来扒一扒它们的区别。

目录

一、new与malloc基本概述

二、主要区别解析

2.1 自由存储区 vs 堆

2.2 指定类型指针 vs void* 指针

2.3 构造函数与析构函数

2.4 异常处理

三、代码示例


一、new与malloc基本概述

newmalloc都是用于在运行时动态分配内存的机制,但它们有着本质的区别。

new是 C++ 语言中的关键字(操作符),专门用于在自由存储区(free store)上分配内存并构造对象。它不仅负责分配内存,还会调用对象的构造函数来完成对象的初始化,从而确保对象在使用前处于正确状态。

delete是与之配套的释放操作,会调用对象的析构函数并释放内存。

这一整套机制是 C++ 提供的内存管理方案,旨在通过自动调用构造/析构函数来简化对象的生命周期管理。

相对而言,malloc是 C 语言标准库中的库函数(包含在<cstdlib><stdlib.h>中),用于在(heap)上动态分配指定字节数的原始内存块。它仅仅分配内存,不进行任何初始化操作

与之配套的free函数用于释放先前通过 malloc 分配的内存。malloc/free 是 C 语言进行动态内存管理的主要手段,需要手动计算所需内存的大小,并在不再需要时显式调用 free 来释放内存,否则将导致内存泄漏。

二、主要区别解析

2.1 自由存储区 vs 堆

new自由存储区(free store)上为对象分配内存。自由存储区是 C++ 为了支持 new 操作而引入的一个抽象概念,凡是使用 new 分配的内存都属于自由存储区。自由存储区在实现上可以基于堆,但不一定等同于堆。例如,可以通过重载operator new使得 new 从静态存储区甚至非堆内存区域分配对象。

C++ 标准并未严格限定自由存储区的具体位置,new 分配的内存位置取决于底层实现,典型情况下是由 C++ 运行时在堆上分配。

malloc直接从上分配内存。堆是操作系统维护的一块用于动态内存分配的内存区域,属于计算机系统的底层概念。当调用 malloc 时,它请求操作系统在堆中开辟一块指定大小的内存,并返回该内存的起始地址。由于 malloc 直接使用堆,它没有类似 C++的内存管理机制。

在实际应用中,new 和 malloc 通常都会在进程的堆内存区域分配空间,但从概念上讲,new 分配的是自由存储区,malloc 分配的是堆。

2.2 指定类型指针 vs void* 指针

new分配内存时,编译器会根据请求的类型信息自动计算所需大小,并返回指向该类型的指针,无需进行类型转换。

例如,int* p = new int;会分配一个 int 所需的内存并返回 int* 类型的指针。这种设计保证了类型安全——编译器会确保 new 返回的指针类型与请求的类型匹配,保证了类型安全。

malloc分配内存时,需要显式指定所需内存的字节数,并且 malloc 返回的是void*类型的通用指针。void* 可以指向任何类型的数据,但本身不包含类型信息。因此,使用 malloc 分配内存时,通常需要将返回的 void* 指针强制转换为所需的指针类型。

例如,int* p = (int*)malloc(sizeof(int));。这里,sizeof(int)计算出 int 类型需要的字节数,malloc 返回的 void* 被显式转换为 int*。这种类型转换增加了出错的机会(如果类型不匹配,可能引发未定义行为)。此外,由于 malloc 无法在编译时进行类型检查,相比 new 缺乏类型安全性。

2.3 构造函数与析构函数

这是 new 与 malloc最核心的区别之一。new在分配内存的同时,会自动调用对象的构造函数来初始化对象。当执行T* p = new T(args);时,编译器会完成两件事:

  1. 调用operator new(底层通常基于 malloc)分配足够大小的原始内存。
  2. 在分配的内存上运行构造函数,将对象初始化为指定状态。

例如,new A()会先调用operator new(sizeof(A))分配内存,然后调用A::A()构造函数,通过 new 分配的对象在使用前就已经完成了必要的初始化。

delete在释放内存时,会先自动调用对象的析构函数来清理对象占用的资源,然后再释放内存。执行delete p;时,会先调用p->~T()析构函数,然后调用operator delete(底层通常基于 free)回收内存。

new/delete 通过自动调用构造/析构函数,实现了对对象生命周期的完整管理。

与之相对,malloc不调用任何构造函数或析构函数。malloc 分配的是原始的、未初始化的内存块,其内容是未定义的。必须手动调用对象的构造函数来初始化,否则对象将处于未初始化状态。

同样地,通过free释放内存时,也不会调用任何析构函数,必须手动调用这些析构逻辑,否则会造成资源泄漏。简而言之,malloc/free 只管内存的分配和释放,不涉及对象的构造和析构,增加了程序员的管理负担。

2.4 异常处理

当内存分配失败(例如系统内存耗尽)时,newmalloc的处理方式也不同。

new默认会抛出异常。C++ 标准规定,如果 new 无法分配足够的内存,它会抛出一个std::bad_alloc类型的异常。分配失败,控制流会被异常机制立即中断。程序员可以通过 try-catch 块来捕获std::bad_alloc异常,从而处理内存分配失败的情况。例如:

try { int* p = new int[10000000]; // 尝试分配超大数组 } catch (const bad_alloc& e) { cerr << "内存分配失败: " << e.what() << endl; // 进行错误处理,例如释放资源、退出程序等 }

malloc在分配失败时返回 NULL 指针。由于 malloc 是 C 语言风格的函数,它没有异常机制,因此通过返回值来指示错误。在使用 malloc 后必须检查返回值是否为 NULL,以判断分配是否成功。如果忽略检查,直接使用空指针,将导致未定义行为(程序崩溃)。例如

int* p = (int*)malloc(sizeof(int) * 10000000); if (p == NULL) { // 内存分配失败的处理 fprintf(stderr, "内存分配失败\n"); exit(EXIT_FAILURE); } // 否则,安全地使用 p...

三、代码示例

构造函数与析构函数的调用与否,是new与malloc的最核心区别。这里我们通过代码示例展示一下

#include <iostream> using namespace std; class A { public: A() : val(66) { cout << "A的构造函数被调用" << endl; } ~A() { cout << "A的析构函数被调用" << endl; } int val; }; int main() { // 使用 new 分配并初始化对象 cout << "--- 使用 new ---" << endl; A* a = new A(); // 会调用 A 的构造函数 cout << "a->val = " << a->val << endl; delete a; // 会调用 A 的析构函数 // 使用 malloc 分配内存但不调用构造函数 cout << endl << "--- 使用 malloc ---" << endl; A* aa = (A*)malloc(sizeof(A)); // 只分配内存,不调用构造函数 // 注意:此时 aa->val 的值是未定义的(垃圾值) // 手动调用构造函数来初始化对象 new(aa)A(); // 使用 placement new 在 aa 所指内存上调用构造函数 cout << "aa->val = " << aa->val << endl; // 手动调用析构函数清理对象,然后释放内存 aa->~A(); free(aa); return 0; }

可以看到,使用 new 时构造函数和析构函数被自动调用,而使用 malloc 时需要手动通过 placement new 调用构造函数,并在 free 前手动调用析构函数。如果省略这些手动步骤,malloc 分配的对象将不会被正确初始化或清理。

写在最后:在现代 C++ 中,推荐优先使用智能指针(如std::unique_ptrstd::shared_ptr)来管理动态分配的对象,而不是直接使用 new/delete。对于智能指针的解读,感兴趣的童鞋可以看这篇文章:C++智能指针 解读_cpp智能指针-CSDN博客

http://www.jsqmd.com/news/640392/

相关文章:

  • 基于遗传算法的最优潮流分析在电力系统设计仿真中的机组出力优化求解
  • SITS2026白皮书发布即生效:3类企业必须在Q3前完成模型对齐升级,否则将丧失国家级项目申报资格
  • 如何在5分钟内掌握gInk:Windows上最高效的免费屏幕标注解决方案
  • 2026年河北节水灌溉企业官方联系方式与行业深度横评:大农场水肥一体化解决方案完全指南 - 精选优质企业推荐榜
  • STM32 独立看门狗(IWDG)程序设计与实现
  • 2026职业规划:开发者的副业赚钱秘籍
  • 手工编程自学教程
  • Vivado工程移植遇IP核被锁?别慌,手把手教你从源码重建自定义IP(附路径问题详解)
  • Jetson Nano新手必看:解决CUDA环境配置失败的3个常见坑(附正确命令)
  • 从寄存器到printf:51单片机串口打印的底层实现与高级封装
  • 粉末称量系统厂家推荐:高口碑、高稳定性供应商 - 品牌推荐大师
  • 2026海外B2B行业社媒运营服务商有哪些,涵盖海外社媒营销服务商与社交媒体获客平台,助力品牌出海曝光(附带联系方式) - 品牌2026
  • 如何设计一个IM单聊架构 长链接业务层 短链接业务层
  • 避坑指南:Grafana 7.5+ Node Graph数据源配置与常见API接口错误排查
  • 缠论量化分析插件:从算法实现到架构设计的深度解析
  • 5分钟搞定《经济研究》论文排版:让学术写作回归纯粹
  • 如何成为团队领导者?技术大牛的软技能清单
  • 2026年4月重庆一次性餐盒/餐盒/一次性打包盒/打包盒厂家综合测评 - 2026年企业推荐榜
  • 2026年大型农场节水灌溉系统怎么选?河北础润节水灌溉官方电话与深度横评指南 - 精选优质企业推荐榜
  • 百度网盘智能提取码解析工具:3秒破解资源访问难题的技术实现
  • 基于列约束生成法CCG的两阶段鲁棒优化问题求解算法:MATLAB实现与案例分析(附详细注释)
  • 春联生成模型-中文-base多场景落地:从个人创作到政务宣传的AI实践
  • 计算机网络 之 【HTTP协议】(域名、url、http协议格式与细节、协议学习通用框架)
  • 函数重要模型
  • 2026海外社媒运营推广公司精选,含海外社媒营销服务商与AI社媒营销管理工具,适配外贸企业需求(附带联系方式) - 品牌2026
  • 2026年液压隔膜计量泵哪个品牌好?国产液压隔膜计量泵制造商推荐及技术解析 - 品牌推荐大师1
  • 从真题到实战:大数据专业视角下的计算机组成与系统结构核心考点解析
  • FanControl风扇控制软件:5分钟完成Windows散热系统智能配置实战指南
  • 2026年自封袋公司哪家强?这几家值得一看,市面上知名的自封袋产品找哪家聚焦优质品牌综合实力推荐 - 品牌推荐师
  • 5分钟高效掌握YuukiPS Launcher:智能游戏启动与管理终极指南