C++的new和delete运算符具体是如何工作的(运算符.工作.delete...)

wufei123 发布于 2025-09-02 阅读(4)
new运算符先计算内存大小,调用operator new分配堆内存,再调用构造函数初始化对象;delete先调用析构函数清理资源,再调用operator delete释放内存。两者必须配对使用,且new对应delete,new[]对应delete[]。与malloc/free不同,new/delete具备类型安全、自动调用构造/析构函数、可重载等特性,推荐在C++中优先使用。自定义operator new/delete可用于内存池、调试或嵌入式场景,但需确保内存分配与释放匹配。动态内存适用于对象大小未知、生命周期超出作用域或需灵活管理大量对象的情况。为避免内存泄漏,应使用智能指针、养成良好习惯并借助工具检测。

c++的new和delete运算符具体是如何工作的

C++的

new
delete
运算符,说白了,就是用来动态分配和释放内存的。
new
负责找一块地方给你用,
delete
负责把用完的地方还回去。但这背后的细节,其实挺有意思的。

解决方案

new
运算符干的事情,大致可以分为三步:
  1. 计算所需内存大小:这步编译器会自动搞定,根据你
    new
    的对象类型,算出需要多少字节。
  2. 分配内存:这才是
    new
    的核心。它会调用一个叫做
    operator new
    的函数,这个函数负责在堆(heap)上找到一块足够大的连续内存块。如果找不到,通常会抛出一个
    std::bad_alloc
    异常(当然,你也可以自定义
    new
    的行为,让它返回空指针)。
  3. 初始化对象:拿到内存后,
    new
    会调用对象的构造函数,在分配到的内存上“盖房子”,把对象真正地创建出来。

delete
运算符则相反,它也分三步:
  1. 调用析构函数:先调用对象的析构函数,把对象“拆房子”,清理对象占用的资源。
  2. 释放内存:然后调用
    operator delete
    函数,把之前
    new
    分配的内存块还给堆,这样这块内存就可以被再次利用了。
  3. 安全处理:虽然不是必须,但好的习惯是将指针设置为
    nullptr
    ,防止悬挂指针。

需要注意的是,

new
delete
必须配对使用,而且要对应正确的形式。比如,用
new
分配的数组,要用
delete[]
释放,否则可能会导致内存泄漏或者程序崩溃。
new
malloc
有什么区别?

这是个经典问题。

malloc
是C语言的函数,而
new
是C++的运算符,它们在内存分配上都能实现类似的功能,但区别还是挺大的。
  • 类型安全:
    new
    是类型安全的,它会返回一个指向正确类型的指针,并且在编译时进行类型检查。
    malloc
    返回的是
    void*
    ,需要手动强制类型转换,容易出错。
  • 构造/析构函数:
    new
    会自动调用对象的构造函数进行初始化,
    delete
    会自动调用析构函数进行清理。
    malloc
    free
    则不会调用构造函数和析构函数,对于C++对象来说,这非常重要,因为很多资源清理工作需要在析构函数中完成。
  • 重载:
    new
    delete
    可以被重载,可以自定义内存分配的行为。
    malloc
    free
    则不能被重载。
  • 异常处理:
    new
    在分配失败时会抛出异常,而
    malloc
    返回
    NULL

简单来说,C++中应该尽量使用

new
delete
,而不是
malloc
free
。 如何自定义
new
delete

C++允许你重载

operator new
operator delete
,这样你就可以自定义内存分配的行为。这在某些特殊场景下很有用,比如:
  • 内存池:为了提高内存分配的效率,可以实现一个内存池,预先分配一块大的内存,然后从中分配小块的内存。
  • 调试:可以重载
    new
    delete
    来跟踪内存分配情况,检测内存泄漏。
  • 嵌入式系统:在资源受限的嵌入式系统中,可能需要自定义内存分配策略。

自定义

new
delete
的基本形式如下:
void* operator new(size_t size) {
  // 分配内存的逻辑
  void* p = malloc(size);
  if (!p) throw std::bad_alloc();
  return p;
}

void operator delete(void* p) noexcept {
  // 释放内存的逻辑
  free(p);
}

void* operator new[](size_t size) { // for array
  // 分配内存的逻辑
  void* p = malloc(size);
  if (!p) throw std::bad_alloc();
  return p;
}

void operator delete[](void* p) noexcept { // for array
  // 释放内存的逻辑
  free(p);
}

需要注意的是,自定义

new
delete
时,要确保分配和释放的内存是匹配的,否则会导致严重的错误。 什么时候应该使用
new
delete

动态内存分配并非总是最佳选择。在以下情况下,考虑使用

new
delete
  • 对象的大小在编译时未知:如果对象的大小需要在运行时才能确定,例如,根据用户的输入动态创建一个数组,那么就需要使用
    new
    来分配内存。
  • 对象的生命周期超出作用域:如果对象的生命周期需要超出创建它的函数的作用域,例如,需要在函数中创建一个对象,并在函数返回后继续使用它,那么就需要使用
    new
    来分配内存。
  • 需要管理大量对象:如果需要管理大量的对象,并且这些对象的生命周期各不相同,那么使用
    new
    delete
    可以更灵活地控制内存的使用。

但也要注意,过度使用

new
delete
可能会导致内存泄漏和碎片化,增加程序的复杂性。在可能的情况下,尽量使用智能指针(如
std::unique_ptr
std::shared_ptr
)来自动管理内存,避免手动
new
delete
。 内存泄漏了怎么办?

内存泄漏是指程序中分配的内存没有被及时释放,导致内存占用越来越高。这是C++程序中常见的问题,也是最难调试的问题之一。

常见的内存泄漏原因包括:

  • 忘记
    delete
    :这是最常见的原因,分配了内存,但是忘记了释放。
  • 异常安全问题:如果在
    new
    delete
    之间抛出了异常,可能会导致
    delete
    没有被执行。
  • 循环引用:在使用智能指针时,如果存在循环引用,可能会导致对象无法被释放。

检测内存泄漏的工具很多,比如Valgrind(Linux)、Visual Studio的内存诊断工具(Windows)等。这些工具可以帮助你找到内存泄漏的位置,并分析泄漏的原因。

预防内存泄漏的最佳方法是:

  • 使用智能指针:尽可能使用智能指针来自动管理内存。
  • 养成良好的编程习惯:在分配内存后,立即编写释放内存的代码,并确保在所有可能的执行路径上都能正确释放内存。
  • 使用内存泄漏检测工具:定期使用内存泄漏检测工具来检查程序是否存在内存泄漏。

总而言之,

new
delete
是C++中动态内存管理的重要工具,理解它们的工作原理,掌握正确的使用方法,才能编写出高效、稳定的C++程序。

以上就是C++的new和delete运算符具体是如何工作的的详细内容,更多请关注知识资源分享宝库其它相关文章!

标签:  运算符 工作 delete 

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。