473,322 Members | 1,719 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,322 software developers and data experts.

Preventing creation of temporary RAII objects

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?

Oct 10 '06 #1
6 1829

Heh,
s/mThingy/Thingy& mThingy/
Guess I ought to check things actually compile before posting them,
sorry...

tomthemig...@googlemail.com wrote:
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?
Oct 10 '06 #2
On 10 Oct 2006 04:53:53 -0700, to**********@googlemail.com wrote:
>A simple RAII wrapper for acquiring a Thingy
....
>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.
Hmm, really?
>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?
Declare a free function:

void ThingyAcquirer (Thingy& thingy, bool furtle = false);

and never define it. Should give a liker error.

Best wishes,
Roland Pibinger
Oct 10 '06 #3
to**********@googlemail.com wrote:
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;
};
I suggest to not do that, better something like this:

class ThingyAcquirerBase
{
protected:
ThingyAcquirerBase (Thingy & thingy) :
mThingy (tingy)
{ }
~ThingyAcquirer ()
{
mThingy.release();
}
void acquire ()
{
mThingy.acquire ();
}
void acquireAndFurtle ()
{
mThingy.acquireAndFurtle ();
}
private:
mThingy;
};

class ThingyAcquirer
{
public:
explicit ThingyAcquirer (Thingy & thingy) :
ThingyAcquirerBase (tingy)
{
acquire ();
}
};

class ThingyAcquirerFurtler
{
public:
explicit ThingyAcquirerFurtler (Thingy & thingy) :
ThingyAcquirerBase (tingy)
{
acquireAndFurtle ();
}
};

--
Salu2
Oct 10 '06 #4
....
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.

Hmm, really?
Indeed. It came as a surprise to me. The relevant part of the standard
is 6.8 - Ambiguity Resolution.

Declare a free function:

void ThingyAcquirer (Thingy& thingy, bool furtle = false);

and never define it. Should give a liker error.
Nice idea. The downside is that in order to use it the ThingyAcquirer
you'll have to use an elaborated type specifier (9.1 para 2):

class ThingyAcquirer acquirer(someThingy, true);

I think this is a small price to pay for avoiding this pitfall
(pratfall?). Where there are 3rd party RAII classes, like the boost
ones, I could have a #ifdef that declares these functions for a
make-sure-I-haven't-made-that-stupid-mistake-with-the-RAII-objects
build. Cool.

Thanks for your help.

Tom

Oct 10 '06 #5
That would be much better here. Unfortunately it isn't possible if the
RAII class is third-party, or if the underlying acquire() method takes
two or more parameters.

Thanks for your help.

Tom

Oct 10 '06 #6
On 10 Oct 2006 11:50:48 -0700, to**********@googlemail.com wrote:
>Declare a free function:

void ThingyAcquirer (Thingy& thingy, bool furtle = false);

and never define it. Should give a liker error.

Nice idea. The downside is that in order to use it the ThingyAcquirer
you'll have to use an elaborated type specifier (9.1 para 2):

class ThingyAcquirer acquirer(someThingy, true);
Actually, that's not really elegant. It's unfortunate that the type
specifier is needed even though the use is not ambigous. Maybe you
should write a macro that creates the object for you??

Best wishes,
Roland Pibinger
Oct 10 '06 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

26
by: codymanix | last post by:
Last night I had several thought about RAII and want to discuss a bit. Why doesn't CSharp support destructors in structs? Wouldn't that make RAII possible like in C++? When the struct goes out of...
23
by: Markus Elfring | last post by:
The class "auto_ptr" implements the RAII pattern for pointer types. It seems that an implementation is not provided for non-pointer values by the STL so far. I imagine to use the "acquisition" for...
8
by: alanstew | last post by:
With the body tag calling out 'window onload', a function with a 'window.open' fails at the 'window.open' line. If I cut out the body tag, the function executes as normal. At first I thought it...
1
by: chettiar | last post by:
Hi, I am dropping an index and recreating it to lower the high water mark. The index creation is taking a lot of time. I am stuck as to why it does so. Is there any way that I can find out why...
9
by: plahey | last post by:
I have been dabbling in Python for a while now. One of the things that really appeals to me is that I can seem to be able to use C++-style RAII idioms to deal with resource management issues. ...
1
by: JohnQ | last post by:
Scenario: A GUI program is developed such that the startup sequence is controlled by the instantiation of a key object which instantiates other objects etc. until it finally arrives at the point...
9
by: Rahul | last post by:
Hi Everyone, class Base { public : Base(int i) { printf("constructor\n"); } void disp() {
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
1
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.