This is covered by any halfway-decent C++ book, but I believe it deserves reiteration: Use the RAII idiom. I don’t think I could explain RAII any better than HackCraft does in The RAII Programming Idiom.
Let me demonstrate how to use RAII with a semi-contrived example. Here’s the pre-RAII code:
|
|
In this case, the resource wrapped is HMODULE
, the resource acquisition function is LoadLibrary()
, and the resource release function is FreeLibrary()
. Beware of resources which have multiple resource release functions, such as Win32’s HANDLE
with FindClose()
and CloseHandle()
; for these cases you will typically have to write multiple RAII classes. I will call the wrapper class HModule
. Here’s how its use will look:
|
|
Things to note:
- I replaced the assignment statement
HMODULE hm = LoadLibrary(_T("user32.dll"));
with the construction statementHModule hm(LoadLibrary(_T("user32.dll")));
. On newer compilers this may not be necessary. HModule
needs to handle the case whereLoadLibrary()
fails—it must not callFreeLibrary()
on an invalidHMODULE
. Be careful of types such asHANDLE
as it uses bothNULL
andINVALID_HANDLE_VALUE
to denote invalid values.HModule
should be transparently convertible to aHMODULE
. This implies either inheriting fromHMODULE
or, preferably, providing a conversion operator toHMODULE
. (Some resource wrapping classes, like STL’sstd::basic_string
, prefer a method rather than a conversion operator (c_str()
in this case), probably to minimize unexpected, implicit conversions. The choice is up to you.)- If a user calls
FreeLibrary(hm);
that will result in a double-free, a potentially dangerous bug. I don’t think there’s a whole lot that can be done about this besides saying “Don’t do that!” - We need to worry assignment and the copy constructor: the default implementations will lead to double-free bugs. A few solutions are: disabling the operators, but this makes the class less useful than it could be; turning assignment/copy construction into transfer of ownership like STL’s
std::auto_ptr
, but this causes some unexpected semantics; or using reference counting like Boost’sshared_ptr
, but this adds often-unneeded complexity and, by itself, introduces the problem of circular references. For simplicity, I will simply choose to disable assignment and the copy constructor.
Given these observations, here’s my version of HModule
:
|
|
Obviously, there’s a lot more that can be done to HModule
, such as supporting release of ownership, reassignment, etc. However, by using RAII classes like HModule
exclusively, you will immediately reap the gains of less thought about resource management, fewer bugs, and you will be one step closer towards exception safety.
BTW, if you don’t want to go to the trouble of writing RAII classes, there’s also ScopeGuard.