Effective C++ item 15: Provide access to raw resources in resource-managing classes.

In last two items I talked about managing resources using RAII objects. Now here comes the practical part. Often we will encounter a situation that a API only accept raw resource instead of RAII objects. For example:

1
2
3
4
5
// You have a shared pointer
std::tr1:;shared_ptr<Foo> foo(createFoo());

// But the API only accept Foo
void acceptFoo(Foo * foo);

In this situation, you need the RAII class return a raw pointer of the resource. And there are commonly two way to do that.

  1. Explicitly provide method to return the raw resource. This is how shared_ptr handles this situation. It provide get() method to return the raw resource it contains. In addition, it also overload operator-> and operator*. I prefer this way cause it’s clear and safe. But some people don’t like this explicit conversion and they will abandon to use this RAII class which, in turn, would increase the chances of leaking memory. In order to satisfy these people, we have the second way to accomplish that.
  2. **Implicitly convert RAII objects to raw resource objects.**How to do this? Let’s see an example.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class Font
    {
    public:
    explicit Font(FontHandle fh):
    f(fh)
    {}

    ~Font(){releaseFont(f);}

    // explicitly convert Font to FontHandle
    operator FontHandle() const
    {return f;}
    ....
    private:
    FontHandle f;
    };

We overload operator FontHandle to implicit convert Font to FontHandle. This provide you the ability to omit .get() no matter the API accept Font or FontHandle. But this method has a downside. The risk is unintentional type conversion. For example:

1
2
3
4
5
Font f1(getFont());
...
// oops! Intent to copy a Font object, but instead implicitly
// converted f1 to FontHandle and then copied that.
FontHandle f2 = f1;

In this way, resource may leak due to the implicitly conversion. That’s why I prefer the first approach cause it’s safe and clear.

Reference:
“Effective C++” Third Edition by Scott Meyers.