Win32, RAII and C++ lambdas
Back when I was last writing serious amounts of C++ for pay (best part of a decade ago), I would end up with a whole bunch of little classes like this one:
class DropFinisher | |
{ | |
private: | |
HDROP drop; | |
DropFinisher & operator = (const DropFinisher &); | |
DropFinisher(DropFinisher &); | |
public: | |
DropFinisher(HDROP _drop) : drop(_drop) {} | |
HDROP get(void) const { return drop; } | |
~DropFinisher() { DragFinish(drop); } | |
}; |
to wrap those fiddly Win32 handle types with RAII behaviour; all much the same, most only being instantiated once, the only real difference being the contained type (which could be templated away) and the destructor behaviour (which isn't so easy).
With modern C++, you could wrap a pointer to the handle in a smart pointer with appropriate custom deleter. Or, avoiding the extra indirection from having to track the HANDLE
and a smart-HANDLE*
, take a leaf from how shared_ptr
is implemented and do:
template<class _Ty> class disposeable : private boost::noncopyable { | |
private: | |
_Ty object; | |
class disposalbase | |
{ | |
public: | |
disposalbase() {} | |
virtual ~disposalbase() {} | |
}; | |
template<class _Uy, | |
class _Dy> class disposer : public disposalbase { | |
_Uy object; | |
_Dy deleter; | |
public: | |
disposer(_Uy _Ut, _Dy _Dt) : object(_Ut), deleter(_Dt) {} | |
~disposer() { deleter(object); } | |
}; | |
std::unique_ptr<disposalbase> disposal; | |
public: | |
template<class _Ty, class _Dx> | |
disposeable(_Ty _X, _Dx _Dt) : object(_X), disposal(new disposer<_Ty, _Dx>(_X, _Dt)) {} | |
_Ty operator()(void) const { return object; } | |
~disposeable() { } | |
}; |
which directly holds a value (expected to be something pointer-like, like the Win32 HWHATEVER
s) with RAII semantics; then in the code:
disposeable<HDROP> drop(reinterpret_cast<HDROP>(wParam), &DragFinish); | |
... | |
DragQueryFileW(drop(), i, &fn[0], fn.size()); |
and apply the same wrapper to different types, injecting the deleter as a lambda:
disposeable<HDC> context(GetDC( NULL ), [] (HDC dc) {ReleaseDC( NULL, dc );}); | |
... | |
disposeable<HCRYPTPROV> provider(hProv, [] (HCRYPTPROV prov) {CryptReleaseContext(prov, 0);}); |
No comments :
Post a Comment