追記:
これが動くのは、そもそも、HMODULEが、ポインター型であることを前提としている。HMODULEがポインターであることを隠すために、わざわざHMODULEという名前を使っているというのに。このコードは、ポータビリティに問題があると言える。
http://cpplover.blogspot.com/2010/02/blog-post_8598.html
そういえば、HMODULEがポインタかどうか一切気にしていなかったのですが、ポインタでなければ使えないですねこれ。まぁ、スマートポインタなのだから、ポインタじゃないものを管理するのはどうか、ということでしょうか。
unique_ptrは名前しか知らなかったのでこの使い方は初めて知りましたが、こんな便利な使い方があるんですね。速くunique_ptrが使える環境に移りたい……。
元エントリ
DLLの動的ロードを行うときに:
- LoadLibraryしたハンドルをFreeLibraryするのが面倒
- デストラクタでFreeLibraryするラッパを書けばいいんじゃね
- ラッパクラスを書くのも面倒!
というわけで、shared_ptrを使おう、と思い立ったのですが、そのまま使用するとshared_ptrが持つ方がHMODULE*になってしまい、色々都合が悪くなります。
boost::shared_ptr<HMODULE> dll(::LoadLibrary(_T("foo.dll")), &::FreeLibrary);
上記のように書くと、コンパイルも通りません。
エラー 1 error C2440: '初期化中' : 'HINSTANCE__ *' から 'HMODULE *' に変換できません。 エラー 2 error C2439: 'boost::shared_ptr<T>::px' : 指定されたメンバは初期化できません。
こういう時は、type_traitsのremove_pointerを使うと良いらしいです。
boost::shared_ptr<boost::remove_pointer<HMODULE>::type> dll(::LoadLibrary(_T("foo.dll")), &::FreeLibrary);
GetProcAddressなど使用するときに毎回getメンバ関数を呼ぶのも気持ち悪いので、その辺りのラッパ関数は作っておいた方が良さそうですね。また、型名が長くなるのでtypedefもした方が良いのでしょう。
こんな感じ?
#include <boost/shared_ptr.hpp> #include <boost/type_traits/remove_pointer.hpp> #include <windows.h> typedef boost::shared_ptr<boost::remove_pointer<HMODULE>::type> dll_handle; dll_handle load_library(TCHAR const* fileName) { return dll_handle(::LoadLibrary(fileName), &::FreeLibrary); } struct get_proc_address { get_proc_address(dll_handle const& handle, char const* name) : handle(handle), name(name) {} template<class F> operator F() const { return reinterpret_cast<F>(::GetProcAddress(handle.get(), name)); } private: dll_handle const& handle; char const* name; }; int _tmain(int argc, _TCHAR* argv[]) { dll_handle dll = load_library(_T("foo.dll")); assert(dll); void (__stdcall * hoge)() = get_proc_address(dll, "hoge"); hoge(); }