VC8.0 で MFC を使わない自作 DLL を作成しました。
その DLL をデバッグ版の MFC アプリケーションにリンクすると
アプリケーションの終了時に Detected memory leaks! が出てくる
ようになりました。
そのダンプ内容を見ると自作 DLL 内のクラスの静的メンバー変数 (std::string 型)
のメモリであることが分かりました。
静的メンバー変数なので最終的にはデストラクタが自動で呼ばれるはずです。
そこでもう少し調べてみると MFC の DLL の後処理で
_AFX_DEBUG_STATE::~_AFX_DEBUG_STATE() から _CrtDumpMemoryLeaks() が呼ばれ
そこで Detected memory leaks! が出ていることが分かりました。
そしてその後に自作の DLL の静的メンバー変数のデストラクタが呼ばれている
ことが分かりました。
デストラクタが呼ばれる前に _CrtDumpMemoryLeaks() が呼べれているので
メモリーリークと判断されてしまいました。
実際にはメモリーリークが起きていないのでメッセージを無視すればいいのですが
本当にメモリーリークが起きたときに気づきにくくなってしまいます。
この問題を解決する方法はないでしょうか?
試しにデバック版の自作 DLL に無理矢理 MFC をリンクしてみました。
そうすると自作 DLL が MFC に依存することになるので、自作 DLL の後処理
の後に MFC の後処理が実行され Detected memory leaks! は出なくなりました。
しかし必要のない MFC をリンクするのはもったいないので避けたいです。
気にする必要はないと思いつつ私も気になる時があります。
次のような仕組みにして終了時に呼ぶのはいかがです?
class Hoge() {
static int *p;
public:
virtual ~Hoge() {
DeleteP();
}
static void DeleteP() {
delete p;
p = NULL;
}
};
たいちう様、アドバイスありがとうございます。
静的メンバ変数は以下のように std::string 型なので
std::string のデストラクタ以外は確保したメモリを解放
できないようになっています。
class Hoge {
static const std::string s;
};
MFC が _CrtDumpMemoryLeaks() ではなく
_CrtSetDbgFlag( _CRTDBG_LEAK_CHECK_DF ) を使っていれば
問題ないのですがわざわざ _CRTDBG_LEAK_CHECK_DF フラグを
消しているようです。
DLLが使うCRTは,DLLのものでないといけないのですか?
つまり,DLL内部のメモリを外部からfree/deleteしたり,その逆をしたり,のような処理
を必要としていますか?
必要としていないのであれば,デバッグ構成だけでもDLLが使うCRTを静的にリンクするも
のに変更してみてはどうでしょうか。
> 静的メンバ変数は以下のように std::string 型なので
> std::string のデストラクタ以外は確保したメモリを解放
> できないようになっています。
この仕様をどこまで変更してよいかによりますが、
次のようなことはできませんか?
intがstringに変わっただけですよ。
class Hoge {
public:
static const std::string * s;
Hoge() {
delete s;
s = new std::string(ここで初期化するとか);
}
virtual ~Hoge() { deleteS(); }
static void deleteS() { delete s; s = NULL; }
};
const std::string * Hoge::s(new std::string(ここで初期化してもいい));
YuO 様
なるほどと思ったのですが残念ながら DLL のヘッダーが標準ライブラリの
クラスに依存しているためアプリケーションと DLL が違う CRT の場合、
誤動作する可能性があります。
そのため boost のようにライブラリのファイル名を CRT などで分けています。
たいちう様
変更箇所が多いこととユーザから見た新しい API の追加が必要なので
この方法はちょっと影響が大きいと思っています。
また、クラスに不変条件が成立しなくなるメソッドがあると扱いが
難しくなるような気がします。