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
は実際には複数のツールのセットであり、そのうちの 1つはたまたまメモリチェックユーティリティであることに注意してください。次のコマンドを発行して、メモリリークを調査できます。
valgrind --tool=memcheck --leak-check=full ./program
チェックが完了すると、次の出力が出力されます。arr
ポインタで delete
を呼び出さなかったため、配列全体でメモリが解放されなかったため、リークの概要でレコード- definitely lost: 10 bytes
になっていることに注意してください。後者は、10 要素の char 配列の実際のサイズです。
==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;
で修正できます。プログラムが終了する前のステートメント。ただし、別のオプションは、スマートポインタの 1つを利用することです。std::unique_ptr
。スマートポインタオブジェクトは、指定されたタイプで初期化でき、new
演算子から返されたポインタを格納します。通常のポインタとの唯一の違いは、std::unique_ptr
に関連付けられたメモリ領域を明示的に delete
する必要がないことです。代わりに、オブジェクトがスコープから外れると、コンパイラが割り当て解除を処理します。
#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;
}