List:MySQL++« Previous MessageNext Message »
From:David Wojtowicz Date:November 2 2005 1:05am
Subject:RE: mysql++ connection/resuse destructor bug
View as plain text  
Chris,

 Thanks for your response.   I did understand that things need to be
destructed in the proper order and how I might attempt that (though I hadn't
thought of using std::auto_ptr, which I've never used before...cool) 
 
 I guess my main point was that it is too easy to create code that looks
perfectly valid (like my example), but had unintended side effects, due to
the hidden nature of destructors being called as objects go out of scope.

Here is an even simpler piece of code that runs into the same problem.

int main(int argc,char **argv) {

  ResUse use;
  Connection con(....);
  Query q=con.query();
  use=q.use("....");
    
}

I don't know if the C++ standard prescribes the order in which destructors
must be called when multiple objects go out of scope or not, but gcc anyway
reasonably destructs them in the reverse order they were constructed in.

In the above code 'con' gets destructed before 'use', which is a problem.
Granted, if you understand the internals of mysql++, then you can see why
this is a problem.  But it's not entirely obvious to anyone else.  After
all, you can do without repercussions:

{string A;  string B;  B="text";  A=B;}

Some possibilities to avoid this pitfall in mysql++:

 1) If ResUse::~ResUse() didn't need to call conn_->unlock(), the problem
would be solved.  I admit I'm not familiar enough with the internals to know
why it is needed and there probably is a very good reason, though I can't
easily see what it is.  I tried commenting it out and recompiling and
running some of my programs with it and didn't run into problems.  Nothing
else calls unlock in result.cpp, and there's no guarantee when ResUse will
be destructed, so it doesn't seem to be important for continuing onto the
next transaction.  But again, I'm probably missing something.

 2) Make the default ctors for ResUse and Result private (which is not
unlike there being no default ctors for Query and Connection)  This would
require making Query a friend of both classes.    It would prevent you from
compiling the problem code example above... and force you to create a ResUse
from an existing object, thus in the proper order.  Though it won't help in
my original example where I explicitly called delete on the Connection.

3) Add a note to the docs, warning about deleting Connection before things
that depend on it go out of scope.


Perhaps it's not a big deal, but I spent like half a day tracking down this
mysterious crash in my code, where it wasn't so obvious due to the number of
different places the various calls are used.

Thanks for listening.


-----Original Message-----
From: Chris Frey [mailto:cdfrey@stripped] 
Sent: Tuesday, November 01, 2005 3:02 PM
To: plusplus@stripped
Subject: Re: mysql++ connection/resuse destructor bug

This behaviour is by design, although this consequence was perhaps
unintended.  Given that a query is based on a connection, and ResUse is
based on a query, the order of destruction must be in the reverse of
construction.

In MySQL terms, it should make sense as well, given that a ResUse only
retrieves data as needed, and so must have a connection involved.




Thread
mysql++ connection/resuse destructor bugDavid Wojtowicz1 Nov
  • Re: mysql++ connection/resuse destructor bugChris Frey1 Nov
    • RE: mysql++ connection/resuse destructor bugDavid Wojtowicz2 Nov
      • Re: mysql++ connection/resuse destructor bugChris Frey2 Nov
      • Re: mysql++ connection/resuse destructor bugChris Frey2 Nov
        • Re: mysql++ connection/resuse destructor bugWarren Young2 Nov
      • Re: mysql++ connection/resuse destructor bugWarren Young2 Nov