C++的
new和
delete运算符,说白了,就是用来动态分配和释放内存的。
new负责找一块地方给你用,
delete负责把用完的地方还回去。但这背后的细节,其实挺有意思的。
解决方案
new运算符干的事情,大致可以分为三步:
-
计算所需内存大小:这步编译器会自动搞定,根据你
new
的对象类型,算出需要多少字节。 -
分配内存:这才是
new
的核心。它会调用一个叫做operator new
的函数,这个函数负责在堆(heap)上找到一块足够大的连续内存块。如果找不到,通常会抛出一个std::bad_alloc
异常(当然,你也可以自定义new
的行为,让它返回空指针)。 -
初始化对象:拿到内存后,
new
会调用对象的构造函数,在分配到的内存上“盖房子”,把对象真正地创建出来。
delete运算符则相反,它也分三步:
- 调用析构函数:先调用对象的析构函数,把对象“拆房子”,清理对象占用的资源。
-
释放内存:然后调用
operator delete
函数,把之前new
分配的内存块还给堆,这样这块内存就可以被再次利用了。 -
安全处理:虽然不是必须,但好的习惯是将指针设置为
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运算符具体是如何工作的的详细内容,更多请关注知识资源分享宝库其它相关文章!
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。