38

I'd like to learn how to use RAII in c++. I think I know what it is, but have no idea how to implement it in my programs. A quick google search did not show any nice tutorials.

Does any one have any nice links to teach me RAII?

Joe Bloggs
  • 531
  • 3
  • 6
  • 14
  • 5
    Not an external link, but you can find some nice answers here: http://stackoverflow.com/questions/395123/raii-and-smart-pointers-in-c – Naveen Apr 14 '10 at 08:28
  • @Naveen - thanks, that one didn't show up in my links when I typed in my title – Joe Bloggs Apr 14 '10 at 08:29
  • 1
    @Joe Bloggs: I use google with site:stackoverflow.com. It produces much better results. – Naveen Apr 14 '10 at 08:30
  • 3
    Which C++ text book are you using that doesn't cover this? –  Apr 14 '10 at 08:36
  • @Neil - not a text book (atm) - I have taught myself c++ gradually over the years from online tutorials and some really basic c++ books (e.g. Teach yourself c++ in 21 days) - I am now trying to learn the more advanced stuff. – Joe Bloggs Apr 14 '10 at 08:42
  • 3
    @Joe Well, there is your problem. You cannot learn C++ from online resources, you need to read at least one (in fact several) book. I recommend accelerated C++, but you can get opinions on others at http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list. And RAII is basic stuff, not advanced. –  Apr 14 '10 at 08:50
  • Joe, I second Neil's advice: Read at least one good C++ book, preferably several of them. RAII is a very old and fundamental technique that novices should learn early on. If you never grasped that, chances are you missed a lot more of the basic concepts. – sbi Apr 14 '10 at 12:56
  • I found a nice tutorial with some minimal examples here : https://www.tomdalling.com/blog/software-design/resource-acquisition-is-initialisation-raii-explained/ – HMD Nov 11 '18 at 10:53

4 Answers4

34

There's nothing to it (that is, I don't think you need a full tutorial).

RAII can be shortly explained as "Every resource requiring cleanup should be given to an object's constructor."

In other words:

Pointers should be encapsulated in smart pointer classes (see std::auto_ptr, boost::shared_ptr and boost::scoped_ptr for examples).

Handles requiring cleanup should be encapsulated in classes that automatically free/release the handles upon destruction.

Synchronization should rely on releasing the mutex/synchronization primitive upon scope exit (see boost::mutex::scoped_lock usage for an example).

I don't think you can really have a tutorial on RAII (not anymore than you can have one on design patterns for example). RAII is more of a way of looking at resources than anything else.

For example, at the moment I'm coding using WinAPI and I wrote the following class:

template<typename H, BOOL _stdcall CloseFunction(H)>
class checked_handle
{
public:
    typedef checked_handle<H,CloseFunction> MyType;
    typedef typename H HandleType;

    static const HandleType     NoValue;

    checked_handle(const HandleType value)
        : _value(value)
    {
    }

    ~checked_handle()
    {
        Close();
    }

    HandleType* operator &()
    {
        return &_value;
    }

    operator HandleType()
    {
        return _value;
    }

private:
    HandleType      _value;

    void Close(const HandleType newValue = NoValue)
    {
        CloseFunction(_value);
        _value = newValue;
    }
};

template<typename H,BOOL _stdcall CloseFunction(H)>
const typename checked_handle<H,CloseFunction>::HandleType 
    checked_handle<H,CloseFunction>::NoValue = 
    checked_handle<H,CloseFunction>::HandleType(INVALID_HANDLE_VALUE);

typedef checked_handle<HANDLE,::CloseHandle> CheckedHandle;
typedef checked_handle<HWINSTA,::CloseWindowStation> WinStationHandle;
typedef checked_handle<HDESK,::CloseDesktop> DesktopHandle;
typedef checked_handle<HDEVNOTIFY,::UnregisterDeviceNotification> DevNotifyHandle;
typedef checked_handle<HWND,::DestroyWindow> WindowHandle;

BOOL __stdcall CloseKey(HKEY hKey);
typedef checked_handle<HKEY,CloseKey> RegHandle;

This class doesn't include assignment and copy semantics (I removed them to provide a minimal example) so returning by value, will cause the handles to be closed twice.

Here's how it's used:

class declaration:

class Something
{
public:
    // ...
private:
    WindowHandle        _window;
};

This member is allocated but I never call ::CloseWindow(_window._handle) explicitely (it will be called when instances of Something go out of scope (as Something::~Something -> WindowHandle::WindowHandle -> ::Close(_window._value) ).

Natan Streppel
  • 5,620
  • 6
  • 33
  • 43
utnapistim
  • 26,020
  • 3
  • 44
  • 78
  • 3
    This can also be accomplished using `boost::shared_ptr` with a custom deallocator. For example, `boost::shared_ptr checked_handle( open_some_handle(), boost::bind< void >( &::CloseHandle, _1 ) );` – Matthew T. Staebler Apr 14 '10 at 21:40
  • 1
    Good point, but I would write that with some typedef-ing at least. I'm not very fond of using a class called "shared_ptr" for something else than a pointer. It leads to mess down the road in maintenance. – utnapistim Apr 26 '10 at 15:12
  • In a sense, a handle IS a pointer. It is a representation of some resource using a primitive data type (that is, it points to a resource using an integer - usually). – Zac Howland Aug 16 '13 at 15:50
3

The wikipedia explanation isn't bad.

Goz
  • 59,899
  • 23
  • 119
  • 199
3

The reference that I personally have found most helpful on the topic of RAII is the book Exceptional C++ by Herb Sutter.

Many of the topics covered in that book are touched on in the Guru of the Week articles by Sutter. Those articles are available at http://gotw.ca/gotw/index.htm.

Matthew T. Staebler
  • 4,518
  • 18
  • 21
2

Item 13 of "Effective C+" is also pretty useful

Chubsdad
  • 24,001
  • 4
  • 68
  • 121