web-dev-qa-db-ja.com

ポインターが削除されたかどうかを検出し、安全に削除する方法は?

InC++ポインタが以前に削除されたかどうかを判断または知る方法は??

以前にコードの別の部分で削除されたポインターを削除しようとすると、処理できない例外がスローされました。

ポインタを確認または削除する方法があるかどうか疑問に思っていましたか?高度なメモリ操作に関する参照。

また、ポインタの未処理の例外をマスターし、保護されたアクセスまたはアクセスが違反です...この種のエラーをマスターしたいです。

他の人々を助け、彼らの利益を共有するために彼らの知識と時間を与えてくれた人々に感謝します


更新

多くの現代のC++開発者コミュニティからの大きなアドバイスは次のとおりです。スマートポインターを使用するか、生のポインターの使用を避けてください。ただし、セキュリティをスローしてメモリを確保するために( ISO_CPP_FAQ )、そしてもちろん、スマートポインターを使用することによる小さなオーバーヘッドを回避したい場合(常に目立たないかもしれませんが、オーバーヘッドがあります)、カスタムを記述できます生のポインタを扱うメソッド[type *]-これは一般的ではありません。 生のポインタよりも常にスマートポインタを優先します

「Going Native 2013」では、一般的なアドバイスとして-生のポインターを使用しないでください。

24
ahmedsafan86

3つの解決策があります。達成したい労力/品質の比率に応じて、いずれかを選択できます。

エレガントで最も正しいソリューション:

スマートポインターを使用すると、deleteを再度手動で呼び出す必要はありません。これは、この問題を克服するための最良の方法です。組み込みのガベージコレクタを持たないC++のような言語に完全に機能するRAIIの原理を利用しています。

あまりエレガントではないが実行可能なソリューション:

削除後にポインターをNULLに割り当てます。 deleteポインターでNULLを呼び出すことは何もしないため、余分なNULLをチェックする必要がなくなりますが、これはhideそれらを目に見えるようにするのではなく、いくつかの問題。

それほどエレガントではないが、より正確なソリューション:

プログラムをクラッシュさせることにより、複数のdelete問題をすべて追い詰めます。 valgrindなどのメモリアナライザープログラムを使用し、コードを修正してこれらの問題をすべて回避することもできます。

27
Alok Save

これは良い質問ですが、手動メモリ管理環境(C/C++やその従兄弟など)で作業する際の基本的な真実の1つは、ポインターを見る良い方法がないということです事後そして、それが有効であるかどうかを尋ねます。一度無効になると消えてしまい、それを見ると爆発する傾向があります。あなたの仕事は、それが二度以上削除されたり解放されたり、それ以降アクセスされたりしないことを確認することです。

このような状況でプログラマーの生活を楽にするために考案されたスマートポインターをぜひご覧ください。 (より伝統的な方法は、気をつけて、めちゃくちゃにすることではなく、Alokが言うように、削除されたことがわかったらポインターにNULLを割り当てることです。)

5
Ben Zotto

C++では、ポインタが以前に削除されたかどうかを判断または知る方法は?

言語標準では、任意のポインターが有効かどうかを判断する法的方法を提供していません。

1つの方法がありますが、コンパイラ/ OS固有です。既存のメモリマネージャにフックするか、独自のメモリマネージャに置き換えて、ポインタ検証専用の機能を提供できます。しかし、それは非常に簡単ではないかもしれません。また、パフォーマンスが重要な場合、この機能に依存することは望ましくありません。

3
Alexey Frunze

ポインタは何も伝えません。設計は次のようにする必要があります。ダイナミックアロケーションを使用している場合、通常はbecauseです。アプリケーションではオブジェクトに特定の有効期間が必要なので、オブジェクトを正しく削除するタイミングがわかります。オブジェクトがコピー可能であるか、スコープに対応する有効期間がある場合、(通常)動的に割り当てません。

もちろん、非常に低レベルのコードには例外があります。std::vectorのようなものを実装する場合、コンパイル時にサイズがわからないため、何らかの動的割り当てを使用する必要があります。しかし、そのような割り当ては逃げるべきではありません。メモリを処理するのは低レベルクラスの責任です。

最後に、バッファオーバーラン、すでに削除されたメモリへのアクセスなどは未定義の動作です。一般に、例外は発生せず、それらを処理する一般的な方法はありません。 (あなたはcan通常、そのようなことが起こったときにシグナルを受け取るように手配しますが、シグナルハンドラーからできることは非常に少ないので、これはあまり役に立ちません。)一般に、あなたが望むものプログラムがクラッシュするのは、その状態がわからないためです。これが当てはまらないまれなケースでは、実装定義の拡張機能がある場合はそれを使用する必要があります。たとえば、VC++で/EHaオプションを使用してコンパイルした場合、通常クラッシュするものはC++例外に変換されます。しかし、それはVC++拡張機能であり、これが発生したときのプログラムの全体的な状態はまだわかりません。空き領域のアリーナが破損しているためである場合、例外をキャッチしてもできることはおそらくあまりありません(スタックを解くときにデストラクタから別の例外が発生する可能性があります) 。

2
James Kanze

私はこのスレッドが古いことを知っています。しかし、他の誰かがこれを読んでいる場合、彼はunique_ptrについて知っている必要があります。 shared_ptrには確かにオーバーヘッドがあります。カウンターはヒープに格納されます。カウンタにアクセスするたびに、プロセッサキャッシュの不一致のリスクがあります。 unique_ptrはより制限されていますが、プレーンポインターと比較してオーバーヘッドはありません。参照カウントが不要な場合は、shared_ptrよりunique_ptrを優先することをお勧めします。もう1つの重要な注意点は、unique_ptrが配列で適切に機能することです。正しく覚えていれば、これはC++ 17以降のshared_ptrにも当てはまります。

1
Martin Fehrs

スマートポインターは、このような問題を回避するためのより良い選択です(ただし、使用する前に完全に理解する必要があります)が、スマートポインターに関連するパフォーマンスの制限について言及したいと思います。理由は、通常、参照用にWin32 APIのInterlockedIncrementカウント。これらの関数は、単純な整数演算よりもかなり低速です。あなたのケースでこのようなパフォーマンスの低下が許容できるかどうかはわかりません。

私が通常していることは(したがって、厄介なバグをデバッグするために数日を費やす必要はありません)、実際のコーディングに移動する前に、私は多くの時間を設計とオブジェクトの寿命に費やしますNULL、私が思う限りそれは良い習慣です。繰り返しになりますが、実際の解決策は、先に進む前に依存関係とオブジェクトの寿命を決定するのにより多くの時間を費やすことです!

1
Saqlain