RAII - short for Resource Acquisition Is Initialization - is one of my favorite programming idioms. In C++, it is very useful to bind resources to the lifetime of objects. Obvious use cases are of course locks and handling heap resources. Every basic RAII example out there will showcase one or the other.
But RAII is in general the perfect tool when symmetric start and end of life handling is required.
In Microsoft’s Component Object Model, for instance, thread CoInitialization can be called multiple times in a nested way - no problem - as long as CoUninitialize is called from the same thread just as frequently.1 So, you’ll wrap it up:
class RaiiCoInit
{
public:
RaiiCoInit()
{
CoInitializeEx(NULL, COINIT_MULTITHREADED);
}
~RaiiCoInit()
{
CoUninitialize();
}
}
and call it like this:
SomeScope
{
RaiiCoInit initialized;
//do COM stuff
CComPtr<IThisIsCom> myComPtr;
}
Another example would be 0MQ sockets. Sockets are bound to a context - and shall be closed before closing the context. As soon as you are using 0MQ infrastructure on a broader scale, things get… well, chaotic, if you don’t plan for it. My approach is to encapsulate context and each type of socket or proxy that I plan to use in RAII structures, and build a tree of these wrappers. Context-wrapper owns its socket-wrappers and proxy-wrappers, and the proxies own their socket-wrappers. As soon as a context or a proxy would be deleted, it recursivly closes and deletes the used sockets. It would look somewhere like this:
class RaiiContext
{
public:
RaiiContext()
{
m_Context = zmq_ctx_new();
m_Socket = std::make_unique<RaiiSocket>(m_Context);
}
~RaiiContext()
{
zmq_ctx_destroy(m_Context);
}
private:
void* m_Context;
std::unique_ptr<RaiiSocket> m_Socket;
}
class RaiiSocket
{
public:
RaiiSocket(void* context)
{
m_Socket = zmq_socket(context, ZMQ_REQ);
zmq_connect(m_Socket, "tcp://localhost:5555");
}
~RaiiSocket()
{
zmq_close(m_Socket);
}
private:
void* m_Socket;
}
Boy, I cannot stand void pointers.
Last but not least I want to mention Andrei Alexandrescu’s Scope Guard - a lovely concept on error strategy. Basically, you’ll write a RAII container for actions that could fail and through exceptions. The container tracks your actions, and if something goes wrong, it will revert all changes. Personally, I despise exceptions. They clutter the code with additional blocks, make it harder to read, are easily forgotten. Of course, they are necessary if something goes horribly wrong, but people tend to use them for minor issues or condition handling. Also, exceptions are costly. Thus I avoid throwing if I can. ScopeGuard wraps and handles those pesky exceptions, so we don’t have to look at them. I am not going to write up example code here, because I am lazy and Andrei’s article is very thorough. Go ahead, check it out!
-
Yeah, it’s not a good idea to do it multiple times. It is costly. But sometimes it might be unavoidable. ↩︎