上記ネタと全く同じ話でGetDCPoliteを用意したよ。これはGetDCしたら必ずReleaseDCをしましょうという教訓をマクロにまとめてしまい、教訓をうっかり忘れても大丈夫なようにしよう、いやむしろ、積極的に教訓は忘れてこっちを使おう!というためのものだ。ソースは以下に。
struct GetDCPolite_t { GetDCPolite_t(){} GetDCPolite_t( HWND hw, HDC* pdc ): _hw(hw){ *pdc = GetDC( hw ); _hdc = *pdc; } ~GetDCPolite_t( void ){ ::ReleaseDC( _hw, _hdc ); } operator bool(){ return !0; } HWND _hw; HDC _hdc; }; #define GetDCPolite( hwnd, pdc ) \ if( GetDCPolite_t tmp = GetDCPolite_t( hwnd, pdc ) ) \ // 上記if文スコープの終端を処理が必ず通過することが前提です。 // 途中のreturnやbreakなどで、本マクロスコープを中断するような // 場合は処理を分岐させる前に必ず、 // ::ReleaseDC( tmp._hw, tmp._hdc ); // をして下さい!
使い方は、今まで
HDC hdc = GetDC( hw ); { // // hdc を使った自分のやりたい描画処理 // } ReleaseDC( hw, hdc );// これを忘れてはならぬ
という感じに書くしかなかったところを、
HDC hdc; GetDCPolite( hw, &hdc ) { // // hdc を使った自分のやりたい描画処理 // }
と書いてすんでしまうという話だ。
最後に、SelectObjectPoliteでも同じ話だけど、これらはいずれも「if文の条件式の中で宣言された変数のスコープはそのif文ブロックのスコープになる」というANSI Cの挙動を利用した、例えばBOOST_FOREACHの実装なんかで使われてるのと同様な手口を利用したものだ。
なのでこのスコープを処理が必ず通過してくることが前提となっている。従って、途中でreturnしたりしてスコープの最後を通過しないような処理では、その際には忘れずに、ReleaseDCやSelectObjectをしないといけなくなってくるよ。そこのところはくれぐれも気をつけてほしい。