2009-07-06 7 views
2

プラグインを提供して機能を拡張できるようにするアプリケーションを作成しました。このようなプラグインはDLLファイルとしてデプロイされ、フレームワークは実行時にピックアップされます。各プラグインは、オブジェクトを作成するためにアプリケーションの存続期間中に複数回呼び出されるファクトリ関数を備えています。これまでのところ、これらのオブジェクトのオーナーシップの問題を処理するために、返されたオブジェクトのシンプルなカウント共有ポインタを使用して、最後の参照が削除されるたびに破棄されるようにしました。DLLメモリマネージャミックスアップ

しかし、これは、オブジェクトがプラグインDLLでnew'edされても、後で(共有ポインタのderef()呼び出しのために)メインアプリケーションで削除されてしまうことは起こりにくいため、Windowsでクラッシュする可能性があります。 - そしてAFAIKこのmalloc/freeミックスアップは、Windowsではno-noです。

これに対する私の現在の解決策は、deref()が 'delete this;'を呼び出さないようにすることです。直接的ではなくむしろ 'release();'プラグインによって実装されなければならず、 'これを削除する';しかし、それぞれのプラグインがこの些細な機能を実装しなければならないというのは非常に面倒です。私はこれまで、便利なマクロプラグインを作成者に提供することでこれを回避しました。誰かに代替案があるのでしょうか?

これまでのところ、プラグインによって寄贈されたすべてのオブジェクトがプラグインに割り当てられ、そこにもリリースされています。もちろん、メインアプリケーションにすべてのメモリを割り当てることもできます彼らは必要に応じて呼び出すことができるプラグインにmallocのような機能を追加)、そこにもリリースしました。この問題は、プラグインの作者にとってはそれほど便利ではないと私は思います。

私はこの問題に関する他の視点に興味があります。

UPDATE:私はちょうど私がそれらをnew'ingし、それらをdelete'ingは常に機能になりますように、プラグインによって返されるオブジェクトの基底クラスに削除し、new演算子と演算子を再実装できることを実現はを呼び出します同じモジュール(すべての割り当てと空きがプラグインやフレームワークで行われるように)。

答えて

3

2つの解決策があります。解決策1は「もっと共有」です。両方のDLLが同じCRT DLL(MSVCの/ MDまたは/ MDd)を使用する場合は、DLLの境界を越えて新規/削除を移動できます。ソリューション2は「シェアを減らす」 - 各DLLに独自のC++ヒープを持たせ、DLL境界をまたいで新規/削除を分割しないようにします。

2

DLLコードがオブジェクトの割り当てを担当する場合は、オブジェクトを解放する責任もDLLコードにあります。私はあなたの問題が参照カウントと "これを削除する"とより多くだと思う。あなたがそのルートに行きたいのであれば、単にオブジェクトをCOMオブジェクトとして実装するだけではいかがですか?これは、COMが解決するように設計された主要な問題のすべての後にあります。

4

メモリが1つのDLLに割り当てられておらず、別のDLLで解放されていることを確認する最も簡単な方法は、プラグインから返されるオブジェクトの基本クラスにoperator newoperator deleteを再実装することです。これらの関数の実装では、 'alloc'と 'free'関数(プラグインをロードするときにメインアプリケーションから渡された関数)を呼び出します。そうすれば、プラグインは 'new'と 'delete'を使用し続けることができますが、メモリは実際にメインアプリケーションに割り当てられて解放されます。

+0

基本クラスのnew演算子とdelete演算子を再実装すると、メモリが使用されますが、そのクラス内で割り当てが行われるのはどうですか?プラグインプロバイダが文字列メンバを追加すると、dllにそのメンバが割り当てられます。しかし、あなたの側のオブジェクトを削除すると、文字列はあなたの側でも破壊されるでしょうか? obj * Create()およびDestroy(obj *)グローバル関数またはAddRef()およびRelease()のものを提供するために投票します。私にとってはるかに安全です。 – eran

+0

@eran私はこのコメントが約3.5年遅れていることを認識していますが、私はあなたの懸念を理解しているかどうかはわかりません。基本クラスで 'operator new'と' operator delete'を再定義すると、派生クラス内から使用された場合にもそれらの演算子が使用されます。例えば、 http://ideone.com/cdNZMpカスタムの 'new' /' delete'実装への2つの呼び出しを示します。その1つのペアは 'Derived :: f'内の' return new Derived;によって返されます。 –

+0

あなたのサンプルコードは、 'operator new'が再実装されたクラスのインスタンスを作成します。私の懸念は、デフォルトの 'new'を使用するフィールドを持つ派生クラスであると思います。そのクラスの「新規」はあなたのプレースメントの対象外です。しかし、もう一度これを読んだので、私は間違っていたと思う。クラス内のすべてのメモリ管理は、基本クラスによって生成されたものが基本クラスによって破壊され、派生クラスによって作成されたものが派生クラスによって破棄される限り、安全です。 – eran