Dllリーク(何)対策
Dllを動的に読み込む場合、明示的に開放しないといけません。これを怠るとメモリを食いまくります。これも一種のメモリリーク(どちらかというとリソースリークか)であり、重大なバグだと思われます。
某所で、同じDllを読み込みまくって無駄にメモリを食ってしまうという事件があった。これはリークではないにしても別の場所で同じDllを使う場合に別々に読むために無駄に使ってしまう。同じDLLなのだから共有すれば無駄なメモリは使わなくてすむはず。
というわけでそういったことをプログラマ側が意識せずに使えるようなクラスがあれば便利なんじゃないかな?かな?というわけで作ってみました。
class DllFile { struct MODULE_DATA{ unsigned int m_nCount; HMODULE m_hDll; }; typedef std::map< std::string, MODULE_DATA > ModuleData; public: DllFile():m_hDll( NULL ){} //コンストラクタ //Dllファイル名を入れると読み込みに行く DllFile( LPCTSTR lpLibFileName ){ this->LoadLibrary( lpLibFileName ); } //Dll読み込み //失敗するとfalseが返ってくる。 bool LoadLibrary( LPCTSTR lpLibFileName ){ this->FreeLibrary(); m_stLibFileName = lpLibFileName; ModuleData::iterator it = m_aModuleData.find( m_stLibFileName ); if( it == m_aModuleData.end() ){ HMODULE hDll = ::LoadLibrary( lpLibFileName ); if( hDll != NULL ){ MODULE_DATA md; md.m_nCount = 1; md.m_hDll = hDll; m_aModuleData[m_stLibFileName] = md; m_hDll = hDll; return true; }else{ m_hDll = NULL; m_stLibFileName.clear(); return false; } }else{ ++(it->second.m_nCount); m_hDll = it->second.m_hDll; return true; } } //デストラクタ virtual ~DllFile(){ this->FreeLibrary(); } //関数を所得 //関数名を渡すと関数ポインタを返す。 FARPROC GetProcAddress( LPCSTR lpProcName ){ if( m_hDll != NULL ){ return ::GetProcAddress( m_hDll, lpProcName ); }else{ return NULL; } } //明示的開放。 //参照カウンタが0になったらモジュールを開放する。 void FreeLibrary(){ if( m_hDll != NULL ){ ModuleData::iterator it = m_aModuleData.find( m_stLibFileName ); if( --( it->second.m_nCount) == 0 ){ m_aModuleData.erase( it ); ::FreeLibrary( m_hDll ); } m_hDll = NULL; m_stLibFileName.clear(); } } private: std::string m_stLibFileName; HMODULE m_hDll; static ModuleData m_aModuleData; }; DllFile::ModuleData DllFile::m_aModuleData;
スマートポインタの応用みたいなもので比較的簡単にできました。
まあ、作ってみたもののDLLを動的に使ったことってないからどの程度実用性があるかは全然わかりません(^^; でもそれなりに便利なんじゃないかなとか勝手に自己満足しておきます(ぉ