16

あるモジュールで何かを新規作成し、別のモジュールで削除すると、VC++ で問題が発生することがよくあります。異なるランタイムの問題。静的にリンクされたランタイムおよび/または動的にリンクされたバージョン管理の不一致を持つモジュールを混在させると、正しく思い出せば問題が発生する可能性があります。

しかし、モジュール間で VC++ 2008 の std::tr1::shared_ptr を使用しても安全ですか?

shared_ptr が何であるかさえ知っているランタイムのバージョンは 1 つしかないため、静的リンクが唯一の危険です (今のところ...)。ブーストのバージョンの shared_ptr はこのように安全に使用できると読んだことがあると思いましたが、レドモンドのバージョンを使用しています...

割り当てモジュールでオブジェクトを解放する特別な呼び出しを回避しようとしています。(または、クラス自体の「これを削除」のようなもの)。これが少しハッキリしていると思われる場合は、これを単体テストに使用しています。既存の C++ コードの単体テストを試みたことがある場合は、どのように創造性を発揮する必要があるかを理解できます。私のメモリはEXEによって割り当てられますが、最終的にはDLLで解放されます(参照カウントが私が思うように機能する場合)。

4

5 に答える 5

16

すべてが同じメモリ管理コンテキストからのものである限り、メモリの解放は安全です。最も一般的な問題 (異なる C++ ランタイム) を特定しました。個別のヒープを持つことは、遭遇する可能性のある、あまり一般的ではない別の問題です。

あなたが言及しなかったが、共有ポインターによって悪化する可能性がある別の問題は、オブジェクトのコードがDLLに存在し、DLLによって作成されたが、DLLの外部の別のオブジェクトがそれへの参照で終わる場合です(共有を介して)ポインター)。DLL がアンロードされた後にそのオブジェクトが破棄された場合 (たとえば、モジュール レベルの静的である場合、または DLL が によって明示的にアンロードされたFreeLibrary()場合)、共有オブジェクトのデストラクタがクラッシュします。

DLL ベースの疎結合プラグインを作成しようとすると、これが問題になる可能性があります。これは、COM サーバーが DLL を要求してアンロードするのではなく、いつアンロードできるかを COM が決定できるようにする理由でもあります。

于 2008-12-05T23:10:09.993 に答える
14

あなたは信じられないほど素晴らしいことshared_ptrがわかり始めています:)

DLL の境界を越えて安全であることは、まさにshared_ptr設計されたものです (もちろん、とりわけ)。

他の人が言ったことに反してshared_ptr、デフォルトはすでに次のようなものであるため、を構築するときにカスタムデリータを渡す必要さえありません

template <typename T>
struct default_deleter {
    void operator()( T * t ) { delete t; }
};

shared_ptr<Foo> foo( new Bar );

と同等です

shared_ptr<Foo> foo( new Bar, default_deleter<Bar>() );

(つまり、デリータのない a などというものはありませんshared_ptr)。

デリータで型消去が実行されるため、delete呼び出される は常にインスタンス化した DLLshared_ptrからのものであり、最後shared_ptrに範囲外になる DLL からのものではありません (つまりshared_ptr、デリータを呼び出すと、元によってそこに置かれた関数へのポインタshared_ptr)。

これを、 (インライン) デストラクタに演算子を直接auto_ptr埋め込む と比較してください。これは、 を破棄するDLLのが使用され、ネイキッド ポインタを削除するのと同じ問題が発生することを意味します。deletedeleteauto_ptr

同じ手法により、常にshared_ptrs に保持されるポリモーフィック クラスは仮想デストラクタを必要としません。これは、最後shared_ptrにスコープ外に出たものが基本クラスに対してインスタンス化されたものである場合でも、デリータは常に適切なデストラクタを呼び出すためです。

于 2011-04-29T17:02:41.530 に答える
7

心配な場合は、deleter 引数を取る shared_ptr コンストラクターの形式を使用してください。デリータは、適切なコンテキストで削除が行われるように、オブジェクトを割り当てたモジュールにコールバックできます。

Boost のドキュメントは、TR1 と 100% 互換性があると主張しているので、これについて誤解を招くものは何もないことを願っています。

http://www.boost.org/doc/libs/1_37_0/libs/smart_ptr/shared_ptr.htm#constructors

于 2008-12-05T23:09:22.477 に答える
2

stdモジュール間で任意のクラスを使用するのと同じくらい安全だと思います。

つまり、モジュールがまったく同じランタイム ライブラリを使用し、まったく同じコンパイラ スイッチとオプションを使用していれば安全です。

各モジュールはその中のすべてのグローバルの独自のインスタンスを取得するため、静的ランタイム ライブラリは使用しないでください。

于 2008-12-05T20:47:56.943 に答える
2

一般的な主題に関して私が見た最良のアドバイスは、メモリが割り当てられたのと同じコンテキストでメモリの割り当てを解除する必要があるということです。ただし、アプリケーションコードが解放するはずのポインターをライブラリが返すことを妨げるものではありません。したがって、同じ一般的な状況であるため、この方法で shared_ptr を渡すことはおそらく安全だと思います。

システムのセマンティクスが、ポインターが実際に (所有権の意味で) exe から dll に転送されることを意味する場合は、auto_ptr の方が適切なソリューションである可能性があります。ただし、ポインターが本当に共有されている場合は、shared_ptr がおそらく最適なソリューションです。

于 2008-12-05T20:56:16.067 に答える