Windows pens are sometimes annoying to remember to clean them (makes GDI with handles and brushes created is a great example). The RAII solution is great, but is it really that it makes one complete Rule of Five RAII class for each type of handle? Of course not! The best I see is one complete common RAII class with other classes, defining what to do when you need to clear the descriptor, as well as other aspects related to the descriptor.
For example, a very simple module class can be defined as follows (just an example):
struct Module { Module() : handle_{nullptr} {} Module(HMODULE hm) : handle_{hm, [](HMODULE h){FreeLibrary(h);}} {} operator HMODULE() const {return handle_.get();} private: Handle<HMODULE> handle_; };
It's all beautiful and dandy, not a destructor or anything else. Of course, however, the ability to write a Handle class does not need a destructor or anything else. Why not use existing RAII methods? One idea would be to use a smart pointer to void , but that would not work. Here, how descriptors are actually declared under normal circumstances:
#define DECLARE_HANDLE(n) typedef struct n##__{int i;}*n DECLARE_HANDLE(HACCEL); DECLARE_HANDLE(HBITMAP); DECLARE_HANDLE(HBRUSH); ...
It actually distinguishes the types of descriptors, which is good, but makes it impossible to use a smart pointer to void . What if instead, since descriptors are, by definition, pointers, a type can be extracted?
My question is whether to make the following safe assumption. It uses a desktop handle that must be closed. Disabling the distinction between generic and unique pointers (for example, FreeLibrary has its own semantics of reference counting), assumes that the descriptor is a pointer and makes a smart pointer that it points to everything in order, or I should not use smart pointers and do Handle realize the RAII aspects themselves?
#include <memory> #include <type_traits> #include <utility> #include <windows.h> int main() { using underlying_type = std::common_type<decltype(*std::declval<HDESK>())>::type; std::shared_ptr<underlying_type> ptr{nullptr, [](HDESK desk){CloseDesktop(desk);}}; }