オブジェクトへの使用可能な参照を確実に保持する方法はありますか?
7 に答える
FastMM4 をメモリ マネージャーとして使用している場合は、クラスがTFreeObjectではないことを確認できます。または、より標準的なケースでは、クラス VMT をチェックする
ことによって、オブジェクトがそれが言うとおりのものであることを検証するルーチンを使用します。
このような ValidateObj 関数がしばらくの間ぶらぶらしていました (Ray Lischner と Hallvard Vassbotn による: http://hallvards.blogspot.com/2004/06/hack-6checking-for-valid-object.html ) 。
ここに別のものがあります:
function ValidateObj(Obj: TObject): Pointer;
// see { Virtual method table entries } in System.pas
begin
Result := Obj;
if Assigned(Result) then
try
if Pointer(PPointer(Obj)^) <> Pointer(Pointer(Cardinal(PPointer(Obj)^) + Cardinal(vmtSelfPtr))^) then
// object not valid anymore
Result := nil;
except
Result := nil;
end;
end;
更新: 少し注意が必要です...上記の関数は、結果が nil または有効な非 nil オブジェクトであることを保証します。メモリ マネージャーが以前に解放したメモリを既に再割り当てしている場合、Obj がユーザーの想定どおりであることを保証するものではありません。
いいえ。参照カウントやガベージコレクターなどを使用して、参照がゼロになる前にオブジェクトが解放されないようにする場合を除きます。
インターフェイスを使用している場合は、Delphi で参照カウントを行うことができます。もちろん、Delphi for .Net にはガベージ コレクタがあります。
前述のように、Delphi の知識またはメモリ マネージャーの内部構造を使用して、有効なポインターまたはオブジェクトをチェックできますが、ポインターを提供できるのはそれらだけではありません。したがって、これらのメソッドでもすべてのポインターをカバーすることはできません。また、ポインターがたまたま再び有効になる可能性もありますが、他の誰かに渡されます。したがって、それはあなたが探しているポインターではありません。あなたのデザインはそれらに依存すべきではありません。ツールを使用して、作成した参照バグを検出します。
他の人が言ったように、決定的な方法はありませんが、所有権をうまく管理すれば、 FreeAndNil ルーチンは、変数が何も指していない場合、変数が nil であることを保証します。
とにかく参照が有効かどうかをチェックするのは、通常は良い考えではありません。参照が有効でない場合、無効な参照を使用している場所でプログラムがクラッシュします。そうしないと、無効な参照が長く存続し、デバッグが難しくなります。
無効な参照でクラッシュするほうがよい理由について、いくつかの参照を次に示します。(彼らは Win32 のポインターについて話しますが、アイデアはまだ関連しています):
標準、いいえ...
そのため、VCL コンポーネントは、オブジェクトの破棄の通知を受けるように登録して、コンポーネントの内部リストから参照を削除したり、プロパティをリセットしたりできます。
したがって、無効な参照がないことを確認したい場合は、次の 2 つのオプションがあります。
- すべてのクラスがサブスクライブできる破棄通知ハンドラーを実装します。
- 参照が別のオブジェクトに広がらないようにコードを修正してください。たとえば、別のオブジェクトのプロパティを介して参照へのアクセスのみを提供できます。プライベート フィールドへの参照をコピーする代わりに、他のオブジェクトのプロパティにアクセスします。
(オブジェクト参照の代わりに) インターフェイス参照を使用すると、コード内で Free を明示的に呼び出す必要がなくなるため、これらの無効なポインターの問題を回避できます。
残念ながら、正しいコードを細心の注意を払って作成する以外に、何かへのポインターが有効であることを 100% 保証する方法はありません。