delete
コンパイル時に以下にコメントされているエラーを検出できるかどうか知りたいのですが?特に、g ++コンパイラについて聞きたいです。
ClassTypeA *abc_ptr = new ClassTypeA[100];
abc_ptr[10].data_ = 1;
delete abc_ptr; // error, should be delete []
std::unique_ptr<ClassTypeA[]>
してからする必要はありません。
delete
コンパイル時に以下にコメントされているエラーを検出できるかどうか知りたいのですが?特に、g ++コンパイラについて聞きたいです。
ClassTypeA *abc_ptr = new ClassTypeA[100];
abc_ptr[10].data_ = 1;
delete abc_ptr; // error, should be delete []
std::unique_ptr<ClassTypeA[]>
してからする必要はありません。
回答:
一般に、コンパイラはそのようなエラーを検出できません。例:クラスのコンストラクターがを使用してデータメンバーを割り当てるnew TypeName[]
が、デストラクタがのdelete
代わりに誤って使用するとしdelete[]
ます。コンストラクタとデストラクタが別々のコンパイル単位で定義されている場合、デストラクタを定義するファイルをコンパイルするときに、コンストラクタを定義する個別にコンパイルされたファイルの使用と矛盾することをコンパイラはどのように知るのですか?
GNUコンパイラに関しては、そうではありません。上記のように、一般的なケースではできません。これは未定義の動作であるため、コンパイラはこのような不一致の新規/削除エラーを検出する必要はありません。UBは、コンパイラベンダーの「脱獄無料」カードです。
valgrindなどのツールは、このような種類の新規/削除の不一致を検出できますが、実行時に検出します。最終的にコンパイルされて実行可能ファイルを形成するすべてのソースファイルを調べる静的分析ツールがあるかもしれませんが、この種のエラーを検出するような静的分析ツールはありません。
に適切なRAIIクラスを使用できますdelete
。これはそれを行う唯一の安全な方法であり、このエラーは、delete
自分自身の呼び出しに遭遇する非常に多くのエラーの1つにすぎません。
常にクラスを使用して、動的な有効期間リソースを管理します。そうすると、型システムは正しいリソース破壊を強制します。
編集:「コードを監査していて変更できない場合はどうなりますか?」あなたはめちゃくちゃです。
この特定のエラー-はい。通常、この種のエラー:残念ながら、ありません!それには、実際に実行せずに実行フローを予測する必要があり、任意のプログラムでは不可能です。(だからほとんどのコンパイラはあなたの例のような単純なケースを検出しようとさえしない。)
したがって、DeadMGの答えは適切なものです。注意を払ってそれを正しくしようとしないでください-人間の注意は誤りやすいです。言語が提供する手段を使用して、コンピューターに注意を向けさせます。
ClassTypeA*
ためif ( rand() % 2 == 1 ) abc_ptr = new ClassTypeA;
、静的型システムの新規と削除の間に行を挿入できます。abc_ptr
配列または動的オブジェクトを指すか、別のオブジェクトまたは配列の一部を示しています。
abc_ptr
あります。そのため、ランタイムは割り当て解除する必要のあるオブジェクトの数を把握しています。
オブジェクトのインスタンス化と破壊は同じスコープ内にあるため、表示する些細なケースはコンパイル時に検出できます。一般に、削除は、インスタンス化と同じスコープ内、または同じソースファイル内でもありません。そして、C ++ポインターの型は、その型の単一のオブジェクトを参照するのか、割り当てスキームを参照するのか、配列を参照するのかについての情報を伝えません。したがって、一般的にコンパイル時にこれを診断することはできません。
可能な特別なケースを診断してみませんか?
C ++には、スコープに関連付けられた動的リソースのリークに対処するためのツール、つまりスマートポインターと高レベルの配列(std::vector
)。
正しいdelete
フレーバーを使用しても、コードは例外安全ではありません。間のコードnew[]
とdelete[]
ダイナミック終了することにより終了し、削除が実行されることはありません。
実行時検出に関する限り、Valgrind
ツールは実行時にこれを検出するのに適しています。時計:
==26781== Command: ./a.out
==26781==
==26781== Mismatched free() / delete / delete []
==26781== at 0x402ACFC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==26781== by 0x8048498: main (in /home/kaz/test/a.out)
==26781== Address 0x4324028 is 0 bytes inside a block of size 80 alloc'd
==26781== at 0x402B454: operator new[](unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==26781== by 0x8048488: main (in /home/kaz/test/a.out)
もちろん、Valgrindはすべてのプラットフォームで実行されるわけではなく、ツールの下ですべての実行時の状況を再現することは常に実用的または可能ではありません。
cppcheck 1.77 and 1.49
> cat test.cc
#include <memory>
int main(){char* buf = new char[10];delete buf;}
http://cppcheck.sourceforge.net/
> cppcheck -x c++ test.cc
Checking test.cc ...
[test.cc:2]: (error) Mismatching allocation and deallocation: buf
clang++ 3.7.1
RHEL7上> clang++ --analyze -x c++ test.cc
test.cc:2:37: warning: Memory allocated by 'new[]' should be deallocated by
'delete[]', not 'delete'
int main(){char* buf = new char[10];delete buf;}
^~~~~~~~~~
1 warning generated.
Clang Static Analyzer std::unique_ptr
は、渡されない場合も検出できます<char[]>
> cat test2.cc
#include <memory>
int main(){std::unique_ptr<char> buf(new char[10]);}
https://clang-analyzer.llvm.org/
> clang++ --analyze -x c++ -std=c++11 test2.cc
In file included from test2.cc:1:
In file included from /opt/rh/devtoolset-4/root/usr/lib/gcc/x86_64-redhat-linux/5.3.1/
../../../../include/c++/5.3.1/memory:81:
/opt/rh/devtoolset-4/root/usr/lib/gcc/x86_64-redhat-linux/5.3.1/
../../../../include/c++/5.3.1/bits/unique_ptr.h:76:2:
warning: Memory allocated by
'new[]' should be deallocated by 'delete[]', not 'delete'
delete __ptr;
^~~~~~~~~~~~
1 warning generated.
これをclangに追加した作業、テスト、見つかった1つのバグへのリンクで以下を更新します。
これはreviews.llvm.org/D4661- "不一致の 'new'と 'delete'の使用を検出することでclangに追加されました。
テストはtest / Analysis / MismatchedDeallocator-checker-test.mmにあります
このバグを発見しました-bugs.llvm.org/show_bug.cgi?id=24819