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

C++之内存分配new与 delete

内存分配

  • C++ `new` 和 `delete` 详解
    • **1. 基本语法**
      • **`new` 运算符**
      • **`delete` 运算符**
    • **2. 工作原理**
      • **`new` 的执行步骤**
      • **`delete` 的执行步骤**
    • **3. 深入理解 `new` 和 `delete`**
      • **原始内存操作**
      • **定位 `new`(Placement New)**
    • **4. 数组的动态分配**
      • **分配与释放数组**
      • **数组初始化**
    • 5.new和delete的实现原理
      • 5.1 内置类型
      • 5.2 自定义类型
    • **6. 常见问题与注意事项**
      • **内存泄漏**
      • **悬空指针**
      • **重复释放**
      • **混用 `delete` 和 `delete[]`**
    • **7. 自定义内存管理**
      • **重载全局 `operator new` 和 `operator delete`**
      • **类特定的内存管理**
    • **8. 与C语言内存管理的对比**
    • **总结**

在这里插入图片描述

C++ newdelete 详解

在C++中,newdelete 是用于动态内存分配和释放的运算符。它们允许程序在运行时管理堆内存,是实现动态数据结构(如链表、树)和灵活资源管理的基础。

1. 基本语法

new 运算符

  • 分配单个对象

    Type* ptr = new Type;         // 默认初始化(内置类型值未定义)
    Type* ptr = new Type(value);  // 直接初始化
    Type* ptr = new Type{value};  // 列表初始化(C++11起)
    
  • 分配数组

    Type* arr = new Type[size];   // 分配包含size个元素的数组
    
  • 值初始化

    Type* ptr = new Type();       // 值初始化为0或默认构造函数
    

delete 运算符

  • 释放单个对象

    delete ptr;  // 调用析构函数(如有)并释放内存
    
  • 释放数组

    delete[] arr;  // 释放数组内存,需使用[]告知编译器释放多个对象
    

2. 工作原理

new 的执行步骤

  1. 内存分配:调用 operator new(或 operator new[] 用于数组)分配原始内存。
  2. 构造函数调用:在分配的内存上调用对象的构造函数(若为类类型)。

delete 的执行步骤

  1. 析构函数调用:对对象调用析构函数(若为类类型)。
  2. 内存释放:调用 operator delete(或 operator delete[])释放内存。

3. 深入理解 newdelete

原始内存操作

  • operator newoperator delete
    底层函数,可被重载以自定义内存分配行为。

    void* operator new(size_t size);      // 分配单个对象
    void* operator new[](size_t size);    // 分配数组
    void operator delete(void* ptr);      // 释放单个对象
    void operator delete[](void* ptr);    // 释放数组
    
  • 示例

    void* raw_memory = operator new(sizeof(int));  // 分配原始内存
    int* ptr = static_cast<int*>(raw_memory);      // 转换为int指针
    *ptr = 42;                                      // 手动赋值
    operator delete(ptr);                           // 释放内存(不调用析构函数)
    

定位 new(Placement New)

  • 在已分配的内存上构造对象:
    void* buffer = operator new(sizeof(MyClass));  // 分配原始内存
    MyClass* obj = new (buffer) MyClass();         // 在buffer上构造对象
    obj->~MyClass();                               // 显式调用析构函数
    operator delete(buffer);                       // 释放内存
    

4. 数组的动态分配

分配与释放数组

int* arr = new int[10];       // 分配10个int的数组
delete[] arr;                 // 释放数组// 多维数组
int** matrix = new int*[5];   // 分配5行
for (int i = 0; i < 5; ++i) {matrix[i] = new int[10];  // 每行10列
}
// 释放
for (int i = 0; i < 5; ++i) {delete[] matrix[i];
}
delete[] matrix;

数组初始化

int* arr = new int[5]{1, 2, 3, 4, 5};  // C++11起支持列表初始化

在对数组进行动态分配时,会自动在之前多分配一块空间用来储存所要开辟的空间个数,以便将来用delete释放空间。

5.new和delete的实现原理

5.1 内置类型

如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是:

new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申
请空间失败时会抛异常,malloc会返回NULL。

5.2 自定义类型

new的原理

  1. 调用operator new函数申请空间

  2. 在申请的空间上执行构造函数,完成对象的构造

delete的原理

  1. 在空间上执行析构函数,完成对象中资源的清理工作

  2. 调用operator delete函数释放对象的空间

new T[N]的原理

  1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请

  2. 在申请的空间上执行N次构造函数

delete[]的原理

  1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理

  2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

6. 常见问题与注意事项

内存泄漏

  • 原因:忘记调用 delete 释放 new 分配的内存。
  • 示例
    void leak() {int* ptr = new int;  // 分配内存// 未释放内存就返回
    }  // 内存泄漏!
    

悬空指针

  • 原因:释放内存后仍保留指向该内存的指针。
  • 示例
    int* ptr = new int;
    delete ptr;
    *ptr = 10;  // 悬空指针解引用,未定义行为
    

重复释放

  • 原因:多次释放同一块内存。
  • 示例
    int* ptr = new int;
    delete ptr;
    delete ptr;  // 重复释放,未定义行为
    

混用 deletedelete[]

  • 错误示例
    int* arr = new int[10];
    delete arr;  // 错误!应使用delete[]
    
    对于内置类型,程序会崩溃;而对于自定义类型,程序不会崩溃。

7. 自定义内存管理

重载全局 operator newoperator delete

void* operator new(size_t size) {void* p = malloc(size);// 可添加内存分配日志、性能监控等return p;
}void operator delete(void* p) noexcept {free(p);// 可添加内存释放日志等
}

类特定的内存管理

class MyClass {
public:static void* operator new(size_t size) {// 自定义分配逻辑return ::operator new(size);}static void operator delete(void* p) noexcept {// 自定义释放逻辑::operator delete(p);}
};

8. 与C语言内存管理的对比

特性C++ new/deleteC语言 malloc/free
类型安全自动推导类型,无需强制转换需要显式转换(如 (int*)malloc()
构造/析构函数自动调用构造函数和析构函数不调用构造/析构函数
初始化支持直接初始化和列表初始化仅分配内存,不初始化值
数组语法直接使用 new Type[size]需要计算总大小(如 malloc(size*sizeof(Type))
智能指针支持与标准库智能指针无缝配合需手动封装为智能指针

malloc/free和new/delete的共同点是:都是从堆上申请空间,并且需要用户手动释放。
不同的地方是:

  1. malloc和free是函数,new和delete是操作符

  2. malloc申请的空间不会初始化,new可以初始化

  3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可, 如果是多个对象,[]中指定对象个数即可

  4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型

  5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常

  6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理释放

总结

  • new/delete 是C++动态内存分配的核心机制,适用于:
    • 需要在运行时确定对象生命周期。
    • 实现动态数据结构(如链表、树)。
  • 优先使用智能指针:现代C++中,std::unique_ptrstd::shared_ptr 能有效避免内存泄漏,提高代码安全性。
  • 谨慎手动管理内存:必须确保 newdelete 配对使用,避免悬空指针和重复释放。
http://www.xdnf.cn/news/7841.html

相关文章:

  • React--函数组件和类组件
  • DL00987-基于深度学习YOLOv11的红外鸟类目标检测含完整数据集
  • 鸿蒙UI开发——实现一个上拉抽屉效果
  • SQL数据处理流程
  • 使用zap,对web应用/API接口 做安全检测
  • VPX3U规格主板的架构实现与性能评估:飞腾D3000+景嘉微JH930平台
  • 《算法笔记》11.8小节——动态规划专题->总结 问题 G: 点菜问题
  • 域名与DNS详解
  • 操作系统————FCFS(先来先服务),优先级调度,SJF(短作业优先调度),RR(时间片轮转调度)四大算法的c++代码实现
  • NGINX常用功能—笔记
  • MyBatis指定构造
  • 【JVM】学习笔记
  • APM32小系统键盘PCB原理图设计详解
  • Webpack 分包策略详解及实现
  • LangGraph(五)——自定义状态
  • 深入剖析原型模式:原理、实现与应用实践
  • 军工与航空航天特种PCB精密制造:猎板如何定义行业技术新标准?
  • Axure项目实战:智慧运输平台后台管理端-订单管理2(多级交互)
  • opencv的直方图
  • 视频监控联网系统GB28181协议中设备控制流程详解
  • Vue3 中 Route 与 Router 的区别
  • 标准IO(2)、文件IO
  • 华为云Flexus+DeepSeek征文|华为云 Dify LLM 平台单机部署教程:一键开启高效开发之旅
  • PDF处理控件Aspose.PDF教程:以编程方式将PDF转换为Word
  • 用户有一个Django模型没有设置主键,现在需要设置主键。
  • JavaEE 初阶文件操作与 IO 详解
  • 网络安全--PHP第一天
  • 国产linux系统(银河麒麟,统信uos)使用 PageOffice实现PDF文件加盖印章和签字功能
  • 快速刷机Android10+Root
  • OpenCV CUDA模块图像特征检测与描述------图像中快速检测特征点类cv::cuda::FastFeatureDetector