T
tomthemighty
A simple RAII wrapper for acquiring a Thingy that has two alternative
acquire methods, acquire() and acquireAndFurtle():
class ThingyAcquirer : private boost::noncopyable
{
public:
explicit ThingyAcquirer (Thingy& thingy, bool furtle = false) :
mThingy(thingy)
{
if(furtle)
mThingy.acquireAndFurtle();
else
mThingy.acquire();
}
~ThingyAcquirer ()
{
mThingy.release();
}
private:
mThingy;
};
When creating objects like this, I (scarily frequently) find myself
typing the wrong thing. Instead of
ThingyAcquirer acquirer(someThingy);
I find my fingers typing:
ThingyAcquirer(someThingy);
This is OK because it causes a compiler error - the compiler parses it
as declaring an object called someThingy, which already exists with a
different type.
However, with the extra parameter this becomes legal C++:
ThingyAcquirer(someThingy, true);
, which compiles happily and releases the thingy immediately!
I've been caught out by this a few times, though so far only ever with
one parameter. If it ever happens with a 2-parameter constructor (such
as those on a couple of boost::thread's RAII locker classes), I'll
probably have a nasty bug on my hands.
Maybe it's just me, but I find this a really easy mistake to make. One
reason is that RAII wrappers often represent something that is
intuitively an action (acquiring a resource), which something stupid in
my subconscious interprets as a function call. Another reason is that I
am not going to be refering to this thing again (not much point - its
only public members are the constructor and destructor), so it's easy
to forget to give it a name.
It seems to me that creating a temporary RAII object is something you
would never, ever want to do, but I can't think of any way to modify
ThingyAcquirer that would make the above code illegal. Can anyone else?
acquire methods, acquire() and acquireAndFurtle():
class ThingyAcquirer : private boost::noncopyable
{
public:
explicit ThingyAcquirer (Thingy& thingy, bool furtle = false) :
mThingy(thingy)
{
if(furtle)
mThingy.acquireAndFurtle();
else
mThingy.acquire();
}
~ThingyAcquirer ()
{
mThingy.release();
}
private:
mThingy;
};
When creating objects like this, I (scarily frequently) find myself
typing the wrong thing. Instead of
ThingyAcquirer acquirer(someThingy);
I find my fingers typing:
ThingyAcquirer(someThingy);
This is OK because it causes a compiler error - the compiler parses it
as declaring an object called someThingy, which already exists with a
different type.
However, with the extra parameter this becomes legal C++:
ThingyAcquirer(someThingy, true);
, which compiles happily and releases the thingy immediately!
I've been caught out by this a few times, though so far only ever with
one parameter. If it ever happens with a 2-parameter constructor (such
as those on a couple of boost::thread's RAII locker classes), I'll
probably have a nasty bug on my hands.
Maybe it's just me, but I find this a really easy mistake to make. One
reason is that RAII wrappers often represent something that is
intuitively an action (acquiring a resource), which something stupid in
my subconscious interprets as a function call. Another reason is that I
am not going to be refering to this thing again (not much point - its
only public members are the constructor and destructor), so it's easy
to forget to give it a name.
It seems to me that creating a temporary RAII object is something you
would never, ever want to do, but I can't think of any way to modify
ThingyAcquirer that would make the above code illegal. Can anyone else?