In Scott Meyrses Effective C++ he provided an exampple of bad usage of implicit conversions along with RAII classes:
class Font { // RAII class
public:
explicit Font(FontHandle fh) // acquire resource;
: f(fh) // use pass-by-value, because the
{} // C API does
~Font() { releaseFont(f ); } // release resource
... // handle copying (see Item14)
private:
FontHandle f; // the raw font resource
};
And the implicit conversion function:
class Font {
public:
...
operator FontHandle() const // implicit conversion function
{ return f; }
...
};
He also provided an example of such bad usage:
Font f1(getFont());
...
FontHandle f2 = f1; // oops! meant to copy a Font
// object, but instead implicitly
// converted f1 into its underlying
// FontHandle, then copied that
And here is what he said:
Now the program has a FontHandle being managed by the Font object f1, but the FontHandle is also available for direct use as f2. That’s almost never good. For example, when f1 is destroyed, the font will be released, and f2 will dangle.
Why will f2 dangle? After copying the FontHandle
resource containing in f1
into f2
, f2
and f1
will be completely independent objects. So, if we release f1
how will it afffect f2
? We apply copying, not moving.
FontHandle is ultimately a pointer itself. f2 is a copy of a pointer outside of the confines of the RAII class. When f1 goes out of scope, it will free the memory pointed at by the fonthandle in f1...but f2 still points to it.
The "FontHandle" moniker is being used for clarity, but lots of time these C APIs, to separate out and hide implementation, will have the API functions take something like a void pointer (void*) that only the guts of the API has the information to dereference and use. Then they may do something like typedef void *FontHandle
so that you know what the void pointer semantically represents.