最初の質問に対する答え: dll の仮想デストラクタが呼び出されます。その場所に関する情報がオブジェクト (vtable) に埋め込まれます。メモリの割り当て解除の場合、ユーザーがどれだけ規律を持っているかによって異なりますIBase
。呼び出す必要があることを知っていてRelease()
、例外が予期しない方向に制御フローをバイパスする可能性があると考える場合、正しいものが使用されます。
しかし、CreateInterface()
返さshared_ptr<IBase>
れた場合は、正しい割り当て解除関数をこのスマート ポインターにバインドできます。ライブラリは次のようになります。
Destroy(IBase* p) {
... // whatever is needed to delete your object in the right way
}
boost::shared_ptr<IBase> CreateInterface() {
IBase *p = new MyConcreteBase(...);
...
return shared_ptr<IBase>(p, Destroy); // bind Destroy() to the shared_ptr
} // which is called instead of a plain
// delete
したがって、DLL のすべてのユーザーは、リソース リークを簡単に防ぐことができます。呼び出しに煩わされRelease()
たり、驚くほど制御フローを迂回して例外に注意を払ったりする必要はありません。
2番目の質問に答えるには:このアプローチの欠点は、他の回答で明確に述べられています:あなたは聴衆であり、あなたと同じコンパイラ、リンカー、設定、ライブラリを使用する必要があります。そして、それらが非常に多くなる可能性がある場合、これはライブラリにとって大きな欠点になる可能性があります. 選択する必要があります: 安全性とより多くの聴衆
ただし、抜け穴の可能性がありshared_ptr<IBase>
ます。アプリケーションで使用します。
{
shared_ptr<IBase> p(CreateInterface(), DestroyFromLibrary);
...
func();
...
}
したがって、実装固有のオブジェクトが DLL 境界を越えて渡されることはありません。それにもかかわらず、ポインタは、 が例外をスローするかどうかにかかわらず、適切なタイミングでshared_ptr
呼び出している の背後に安全に隠されています。DestroyFromLibrary
func()