2017-02-14 12 views
0
/* 

1つ以上のダイナミックリンクライブラリ(DLL)をアドレス空間にロードするWindowsプロセスでは、そのアドレス空間をすべてのロード済み領域DLL - これらのDLLはプロセスのアドレス空間内の任意のメモリに読み書きできます。ただし、オブジェクトがヒープ上に割り当てられると、各モジュール(プロセスのロードされたDLLのうちの1つである.exe)は、独自のヒープから割り当てられます。このため、割り振りを実行した同じヒープに対してメモリーを割り振り解除することが重要です。すべては私には理にかなっていると私は私が整理物事を保つためにstd::unique_ptrを使用するかもしれないと思ったことWindows DLLモジュールの境界を越えてヒープ割り当てリソースをクリーンアップする問題

。これは私が使ったアプローチです。 (私は現時点では私のコンパイラが手元にありませんが、私はこれらのスニペット/擬似コードは、私の意図を伝えるのに十分明らかになると思う。

*/ 

Library.h

class ILibrary 
{ 
    public: 
    virtual void DoStuff() = 0; 
}; 

struct Deleter 
{ 
    void operator()(ILibrary *p) 
    { 
    delete p; 
    } 
}; 

typedef std::unique_ptr<ILibrary, Deleter> Ptr; 

//*MyLibrary.dll* 
//Includes Library.h 
//Exports: 

void GetMyLibrary(Ptr & library) 
{ 
    library = Ptr(new MyLibrary); // point (1) 
} 

//**Program.exe** 
//Includes Library.h 
//Imports MyLibrary.dll (GetMyLibrary export) 

int main() 
{ 
    Ptr local; 
    MyLibrary->GetMyLibrary(local); 
    local->DoStuff(); 
} // heap corruption on cleanup 

あなたは私は私のライブラリへのポインタを保持する変数localを作成します。私のライブラリとメインプログラムの両方が同じヘッダLibrary.hを使用することがわかります。(DLL内で呼び出さ)GetMyLibrary方法私は渡された基準にnew unique_ptrを割り当て、割り当て私は「Deleted」を「ポイント1」で使用した私のメインプログラムの変数localに最初に割り当てられたDeleterではなく、クリーンアップに使用されるDLLのext。意味、地元がスコープ外になったとき、私はDELETERは、DLLのコンテキストから呼び出すことがしたいので、DLLのDELETERをトリガーするためにそのクリーンアップではなく、最初はそれに割り当てられた1(すなわち、私はlibrary = Ptr(new MyLibrary)代わりのlibrary.reset(new MyLibrary)を使用したいです)

とにかく、プログラムは、除外中、ローカルunique_ptrが破壊されたとき以外は、ヒープ破損例外(デバッグ時)が表示され、間違ったヒープを削除していると考えられます。 unique_ptrは私が期待どおりに動作していません)

最終的に、私は問題を解決しました。これははるかにクリーンなようですが、なぜ上記のアプローチが失敗したのか不思議でした。

+1

「** **ヒープ」 - それはあなたの問題の大部分です。限りのWindowsに関しては、** **ヒープは[ 'GetProcessHeap'](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366569(V = VS.85)によって返されます.aspx)と、そのヒープ_is_はEXEとDLLの間で共有されます(したがって、 "プロセスヒープ"という名前)。 – MSalters

+0

リンクをありがとう、私はそれを読み上げるでしょう。 – charunnera

答えて

1

あなたデリータはunique_ptrをの一部であり、ポインタがスコープの外に出たとき、メインから呼び出されます。

あなたはDLLにGetMyLibrary()/FreeMyLibrary()を提供し、そこにメモリの割り当て/割り当て解除を扱う(アプリケーション側でRAIIを使用して)、またはGetMyLibrary()にアロケータを渡すと、メモリの割り当てと解放のアプリケーションの責任を作る必要があるのいずれか。

+0

あなたの答えをありがとう...私はまだ少し混乱しています。私はGet/Free輸出の使用についてあなたが言っていることを得ています...これは、これまで私がこれまで行ってきたことですが、上記のアプローチがなぜ壊れているのかは分かりません。 GetMyLibraryエクスポートを呼び出すと、DLLのコードが実行され、unique_ptrをインスタンス化し、ライブラリのインスタンスを新規作成します。そのunique_ptrには、対応するオブジェクトを解放するためのカスタムDeleter(DLLコードに存在)があります。DLLのunique_ptr(refを介して)をメインのunique_ptrにコピーすると、呼び出されるDLL内のDeleterが呼び出されます。 – charunnera

+0

(あなたが言及したFreeMyLibrary()関数の呼び出しと同様です)何が欠けていますか? – charunnera

+1

ここで 'Deleter'型は' Ptr'型の一部です。 'unique_ptr'は、' main() 'の中で起きる' get_deleter() 'への構築や最初の呼び出し時に' Deleter'型のこのオブジェクトをインスタンス化します。単純な関数をdeleterとして渡すこともできますが、dll/appの境界で 'unique_ptr'を使うのは良い考えではありません。 dllが別のコンパイラや標準ライブラリ、あるいはその異なるバージョンでコンパイルされたとします。 – w1ck3dg0ph3r

関連する問題