避免 C++ 中的内存泄漏
本文将演示有关如何避免 C++ 中的内存泄漏的多种方法。
使用 delete
操作符释放每个 new
分配的内存块
内存泄漏是直接与原始动态内存接口进行交互的程序的常见问题,这给程序员增加了负担,以相应的方法释放每个分配的内存。在 C++ 中可以访问多个用于内存管理的接口,以及一些特定于平台的系统调用,这些接口实质上代表了可用于此目的的最低级别的功能。在大多数情况下,常规程序应仅使用特定于语言的功能(例如 new
和 delete
操作符)进行手动内存管理,或使用智能指针进行自动内存重新分配。
内存泄漏最易受攻击的方法是使用 new
/delete
操作符直接管理堆内存。请注意,从 new
调用返回的每个指针都应传递给 delete
操作符,以将相应的内存块释放回系统,否则可能会耗尽内存。例如,下面的程序分配一个 10 个元素的 char
数组,并且在程序退出前不释放它。因此,该程序据说会发生内存泄漏。
#include <iostream>
using std::cout;
using std::endl;
constexpr int SIZE = 10;
int main()
{
char *arr = new char[SIZE];
for(int i = 0; i < SIZE; ++i) {
arr[i] = (char)(65 + i);
cout << arr[i] << "; ";
}
cout << endl;
return EXIT_SUCCESS;
}
可以使用 valgrind
程序检测内存泄漏,该程序是一个命令行实用程序,可以在已编译的程序文件上执行。请注意,Valgrind
实际上是一组多个工具,其中一个恰好是内存检查实用程序。可以发出以下命令来调查内存泄漏。
valgrind --tool=memcheck --leak-check=full ./program
完成检查后,将输出以下输出。注意,由于我们没有在 arr
指针上调用 delete
,所以整个数组导致未释放的内存,因此在泄漏摘要中记录了 - definitely lost: 10 bytes
。后者是 10 个元素的字符数组的实际大小。
==13732== HEAP SUMMARY:
==13732== in use at exit: 10 bytes in 1 blocks
==13732== total heap usage: 3 allocs, 2 frees, 73,738 bytes allocated
==13732==
==13732== 10 bytes in 1 blocks are definitely lost in loss record 1 of 1
==13732== at 0x483C583: operator new[](unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==13732== by 0x1091FE: main (tmp.cpp:11)
==13732==
==13732== LEAK SUMMARY:
==13732== definitely lost: 10 bytes in 1 blocks
==13732== indirectly lost: 0 bytes in 0 blocks
==13732== possibly lost: 0 bytes in 0 blocks
==13732== still reachable: 0 bytes in 0 blocks
==13732== suppressed: 0 bytes in 0 blocks
==13732==
==13732== For lists of detected and suppressed errors, rerun with: -s
==13732== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
使用 std::unique_ptr
自动释放堆对象
前面的例子代码可以通过在程序退出前的 delete [] arr;
语句来解决。虽然,另一种选择是利用智能指针之一,例如,std::unique_ptr
。可以使用给定的类型初始化智能指针对象,并存储从 new
操作符返回的指针。与常规指针的唯一区别是与 std::unique_ptr
相关的存储区域不需要显式地 delete
-d。相反,一旦对象超出范围,编译器将负责释放。
#include <iostream>
#include <memory>
using std::cout;
using std::endl;
constexpr int SIZE = 10;
int main()
{
std::unique_ptr<char[]> arr(new char[SIZE]);
for (int i = 0; i < SIZE; ++i) {
arr[i] = (char)(65 + i);
cout << arr[i] << "; ";
}
cout << endl;
return EXIT_SUCCESS;
}
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn