web-dev-qa-db-ja.com

ヒープから配列を削除する

私の質問は、ヒープメモリから配列を削除することについてです。私は本を​​読み、 このブログ およびその他のリソース このような 、そしてそれらのすべては、ヒープから配列を削除するには、後に[]を使用する必要があると述べましたdelete関数なので、[]を使用せずにコードを記述すると、メモリリークが発生します。

たとえば、以下のプログラムを検討してください

int *s = new int[10];
delete [] s;

valgrindパッケージを使用してLinuxでこの小さなプログラムをテストしました(このパッケージは、不適切なコーディングによってリークされたメモリがどれだけ生成されるかを確認できます)。Linuxの以下のコマンドで、すべてが正常であることがわかりました。

Sudo valgrind --leak-check=full ./<path_to_exe_file>

これがLinuxコマンドの出力です

 ==4565== HEAP SUMMARY:
 ==4565==     in use at exit: 0 bytes in 0 blocks
 ==4565==   total heap usage: 1 allocs, 1 frees, 40 bytes allocated
 ==4565== 
 ==4565== All heap blocks were freed -- no leaks are possible

しかし、[]を使用せずにdeleteを使用しようとしたときに、valgrindの出力を確認すると、すべてのヒープメモリが解放されているので、正しいのでしょうか。またはvalgrindは、ヒープ全体が解放されておらず、配列の一部がまだそこにあることを知りませんでした!! ?? valgrindがこの種のリークされたメモリを検出できなかった場合、それを検出できるパッケージはありますか。

11
Saeed Masoomi

[]を使用せずに配列でdeleteを呼び出すと、未定義の動作が発生します。未定義の動作は、アレイが正しく削除されている可能性があります。これは、観察したとおりのようです。ただし、これに頼ることはできません。

5

マーティンブロードハーストはすでに正しい 言語-弁護士の答え を与えています。私は技術的な詳細の答えを与えるつもりです:

deleteで_delete[]_を使用することのポイントは、渡されたポインターが配列を指しているのか、単一のオブジェクトを指しているのかをdelete演算子が知る方法がないということです。そのため、deleteは単一のオブジェクトのみを削除しますが、_delete[]_は配列のサイズを回復するために追加の魔法を呼び出し、すべての要素の削除に進みます。

現在、削除は2つの異なる部分で構成されています。

  1. オブジェクトは、デストラクタを呼び出して破棄する必要があります。配列の場合、これは、配列要素ごとに1つのデストラクタ呼び出しを意味します。

  2. 使用されたメモリは、再利用できるように空きとしてマークする必要があります。これは、C++のグローバルoperator delete()の仕事です。配列は連続して格納されるため、これは配列全体に対する1回の呼び出しです。

valgrindはメモリのみを考慮します。そのため、malloc()free()operator new()operator delete()などのメモリ割り当て関数をフックします。

_delete[]_の代わりにdeleteを呼び出すと、最初のオブジェクトが破棄され、ポインターがoperator delete()に渡されます。 operator delete()は、メモリ領域内に格納されたオブジェクトを認識していません。いずれにせよ、オブジェクトはすでに破棄されているため、メモリ領域を空きとして正常にマークします。 valgrindはこのoperator delete()呼び出しを確認し、すべてのメモリが自由に再利用できるので満足しています。ただし、コードは最初の配列要素を除くすべての要素を適切に破棄できませんでした。そして、これは悪いです。

2
cmaster