C++ でのメモリリークの回避

胡金庫 2023年10月12日
  1. delete 演算子を使用して、各 new に割り当てられたメモリブロックを解放する
  2. std::unique_ptr を使用して、ヒープオブジェクトを自動的に解放する
C++ でのメモリリークの回避

この記事では、C++ でのメモリリークを回避する方法に関する複数の方法を示します。

delete 演算子を使用して、各 new に割り当てられたメモリブロックを解放する

メモリリークは、生の動的メモリインターフェイスと直接対話するプログラムに共通の問題であり、対応するメソッドで割り当てられた各メモリを解放するためにプログラマに負担をかけます。C++ でアクセス可能なメモリ管理用の複数のインターフェイスと、プラットフォーム固有のシステムコールがいくつかあります。これらは、基本的に、この目的に利用できる最低レベルの関数を表します。ほとんどの場合、通常のプログラムでは、手動のメモリ管理には newdelete 演算子などの言語固有の機能のみを使用するか、自動メモリ割り当て解除にはスマートポインタを使用する必要があります。

メモリリークの最も脆弱な方法は、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;
}
著者: 胡金庫
胡金庫 avatar 胡金庫 avatar

DelftStack.comの創設者です。Jinku はロボティクスと自動車産業で8年以上働いています。自動テスト、リモートサーバーからのデータ収集、耐久テストからのレポート作成が必要となったとき、彼はコーディングスキルを磨きました。彼は電気/電子工学のバックグラウンドを持っていますが、組み込みエレクトロニクス、組み込みプログラミング、フロントエンド/バックエンドプログラミングへの関心を広げています。

LinkedIn Facebook

関連記事 - C++ Memory