web-dev-qa-db-ja.com

DLLで宣言されたグローバル変数はどうなりますか?

DLLをC++で記述し、重要なデストラクタでクラスのグローバルオブジェクトを宣言するとします。デストラクタは、DLLアンロードされていますか?

38
Dima

Windows C++ DLLでは、すべてのグローバルオブジェクト(クラスの静的メンバーを含む)はDLL_PROCESS_ATTACHでDllMainを呼び出す直前に構築され、DLL_PROCESS_DETACHでDllMainを呼び出した直後に破棄されます。

ここで、3つの問題を考慮する必要があります。

0-もちろん、グローバルな非constオブジェクトは悪です(しかし、あなたはすでにそれを知っているので、マルチスレッド、ロック、godオブジェクトなどについては触れません)

1-オブジェクトまたは異なるコンパイル単位(つまり、CPPファイル)の構築順序は保証されないため、2つのオブジェクトが2つの異なるCPPでインスタンス化されている場合、オブジェクトAがBの前に構築されることは望めません。これは、BがAに依存する場合に重要です。解決策は、同じコンパイル単位内でオブジェクトをインスタンス化する順序が構築の順序(およびその逆)になるように、同じCPPファイル内のすべてのグローバルオブジェクトを移動することです。破壊の)

2-DllMainで禁止されていることがある。これらのものも、コンストラクタではおそらく禁止されています。したがって、何かをロックすることは避けてください。この件に関するレイモンドチェンの優れたブログをご覧ください。

http://blogs.msdn.com/oldnewthing/archive/2004/01/27/63401.aspx

http://blogs.msdn.com/oldnewthing/archive/2004/01/28/63880.aspx

この場合、遅延初期化は興味深いものになる可能性があります。クラスのいずれかのメソッドを呼び出すまで、クラスは「初期化されていない」状態(内部ポインターはNULL、ブール値はfalseのまま)のままで、その時点でクラスは自身を初期化します。これらのオブジェクトをメイン(またはメインの子孫関数の1つ)内で使用すると、DllMainの実行後に呼び出されるため、問題ありません。

3-もちろん、DLL Aの一部のグローバルオブジェクトがDLL Bのグローバルオブジェクトに依存している場合は、DLL読み込み順序、および依存関係。この場合、直接または間接的な循環依存関係を持つDLLは、非常に多くの頭痛の種を引き起こします。最適な解決策は、循環依存関係を解消することです。

PS:C++では、コンストラクターがスローする可能性があり、DLLロードの途中で例外を必要としないため、グローバルオブジェクトが例外なしで例外を使用しないようにしてください。非常に非常に良い理由です。正しく記述されたデストラクタはスローする権限がないため、この場合、DLLアンロードは問題ありません。

37
paercebal

Microsoftのこのページでは、DLL初期化とグローバルの破棄について詳しく説明します。
http://msdn.Microsoft.com/en-us/library/988ye33t.aspx

6
Mark Ransom

.dllをリンクするときに実行される実際のコードを確認するには、_%ProgramFiles%\Visual Studio 8\vc\crt\src\dllcrt0.c_をご覧ください。

検査から、dll CRTによって維持されている内部参照カウントがゼロに達すると、デストラクタが_cexit()を介して呼び出されます。

4
MSN

アプリケーションが終了したとき、またはDLLがアンロードされたときのいずれか早い方のタイミングで)呼び出されます。これは、コンパイル対象の実際のランタイムによって多少異なることに注意してください。

また、タイミングと順序の両方の問題があるため、重要なデストラクタにも注意してください。あなたのDLLがアンロードされる可能性があります a DLLデストラクタが依存しているため、明らかに問題が発生します。

3
Philip Rieck

FdwReason = DLL_PROCESS_DETACHパラメータを指定したDllMainが呼び出されると、DLLがアプリケーションによってアンロードされます。これは、グローバル/静的オブジェクトのデストラクタが呼び出される前の時間です。

1
INS

拡張子が* .exeのWindowsバイナリイメージファイルでは、*。dllは PE形式 です。このようなファイルにはエントリポイントがあります。あなたはのようなdumpbinツールでそれを見ることができます

dumpbin/headers dllname.dll

MicrosoftのCランタイムを使用する場合、エントリポイントは* CRTStartupまたは* DllMainCRTStartupのようになります。

このような関数は、cおよびc ++ランタイムの初期化を実行し、実行をそれぞれ(main、WinMain)またはDllMainに委任します。

Microsofts VCコンパイラを使用している場合は、この関数のソースコードを自分のVCディレクトリで確認できます。

  • crt0.c
  • dllcrt0.c

DllMainCRTStartupプロセスは、dllのアンロード中に通知DLL_PROCESS_DETACHを取得するときに、通常のシナリオで.dataセクションからグローバル変数を初期化/非初期化するために必要なすべてのものを処理します。例えば:

  • プログラムの起動スレッドのメインまたはWinMainが制御フローを返す
  • freeLibraryを明示的に呼び出し、use-dll-counterがゼロ
1
bruziuz