5

提供されているDestroyメソッドを使用する以外に、クラス階層からオブジェクトを削除できないようにしたいと思います。

理論的根拠は、この階層のオブジェクトは、別のスレッドがオブジェクトを使用しているときにオブジェクトが削除されないようにするために、オブジェクト自体の破棄を開始する前に特別な書き込みミューテックスを取得する必要があるということです。

参照カウントでこの問題を防ぐことができることはわかっていますが、パフォーマンスへの潜在的な影響とメモリ割り当ての観点からも、システムに大きな変化をもたらすでしょう。

どういうわけか効率的/スマートにすべてのデストラクタを保護して、部外者がDestroyを使用しなければならないときに、子クラスが親のデストラクタを呼び出すことができるようにする方法はありますか?

私が思いついた安全な(つまり、腐敗しない)解決策の1つは、すべてのデストラクタをプライベートにし、各派生クラスを基本クラスのフレンドとして宣言することですが、よりエレガントで、手動ではなく、より簡単なものを好みます維持する(基本クラスから派生するために基本クラスを変更する必要がないなど)。

このようなものはありますか?たぶん、私が望むように物事を「機能させる」いくつかの賢いトリックですか?

ps。私が今のところ選択した解決策は、すべての場合に誰もがdeleteを呼び出さないようにするのではなく(基本クラスで保護されただけです)、この状況を検出し、基本クラスのデストラクタでabortを呼び出すことです。

4

4 に答える 4

1

フィードバックとディスカッションをありがとうございます。はい-私の自然な最初の選択となることを行うことは不可能であることが証明されました:((「仮想性」と同じように、デストラクタの「保護」を派生クラスで有効にする)。

この特定の場合の私の解決策(以前の合意に違反する新しい派生クラスを導入し、ソリューションを1か所/保守可能(派生クラスでのコード重複なしなど)に保つことで、間違いを犯す可能性のあるすべての潜在的な問題を解決します)は次のとおりです。

  1. 私が見つけることができるすべての既存のクラス階層デストラクタを保護する
  2. これらのオブジェクトの破棄を開始するために使用できる基本クラスのDestroyメソッドを提供します-メソッドが呼び出されると、破棄されたオブジェクトに適切に破棄されたというフラグが点灯し、それに対してdeleteが呼び出されます
  3. 基本クラスのデストラクタで(一度取得したら)フラグをチェックします-設定されていない場合は、誰かが新しいクラスを導入して直接削除を呼び出すか、他の方法でコンパイラの保護チェックを回避したことを意味します(友情などを乱用しました)-この場合、問題を無視/見逃すことのできないように、アプリケーションを中止します
于 2013-03-20T09:40:29.840 に答える
1

言語によって提供される生涯メカニズムを再発明しようとしないでください。

クラスのオブジェクトを正しく初期化するには、それ自体をクリーンアップできる必要もあります。

コンストラクターで、ミューテックス、またはデストラクタで使用できるミューテックスを取得する手段のいずれかを渡します。

于 2013-03-06T11:05:56.180 に答える
1

私は同じニーズを持っていましたが、別の理由でした。当社のフレームワークでは、ほぼすべてのクラスが共通のBaseObjectクラスから派生しています。このオブジェクトは、参照カウントを使用してその寿命を決定します。には、特に次の 3つBaseObjectメソッドretain()release()あります。演算子は、保持カウントが0に達したときに内部でのみ呼び出されます。誰も直接呼び出すことは想定されておらず、インスタンスをスタックに置くことも望ましくありません。autorelease()deleterelease()deleteBaseObject

したがって、すべてのデストラクタはprotectedorにする必要がありますprivate。これを強制するために、言語からは不可能であることはわかっているので、ソース ディレクトリ内のすべてのデストラクタを探してレポートを作成する Perl スクリプトを作成しました。その後、ルールが尊重されていることを確認するのは比較的簡単です。

スクリプトを公開しました。こちらから入手できます: https://gist.github.com/prapin/308a7f333d6836780fd5

于 2014-07-01T20:44:30.360 に答える
0

それはテストの助けを借りて行うことができます。保護されたデストラクタを持つクラスの場合、2 つのテスト ケースが必要です。

  1. そのようなオブジェクトを作成するだけでコンパイルに失敗する 1 つの関数 (1 つのファイル内)
  2. コンパイルする派生クラスを持つオブジェクトを作成する 1 つの関数 (2 番目のファイル内)。

両方のテスト ケースが機能する場合、クラスが思いどおりに保護されていることを確認できると思います。

ビルドシステムで実装できるかどうかはわかりませんが、git hubに bjam (boost から) を使用した例があります。コードはシンプルで、gcc と msvc で動作します。bjam がわからない場合は、Jamroot.jam を参照してください。この単純な例がどのように機能するかは、これ以上コメントしなくても明らかだと思います。

于 2013-03-06T14:17:59.927 に答える