[Interest] Double destruction of Qt objects in Qt example code?
Till Oliver Knoll
till.oliver.knoll at gmail.com
Sun Aug 19 17:18:34 CEST 2012
Am 19.08.12 01:29, schrieb K. Frank:
> ...
> It then calls the destructor of its child, quit, which is incorrect
> because quit is a local variable.
>
> To be more precise, it ought to say is "It then calls delete on its child ..."
> As I understand c++, it is technically legal -- for the time being -- to call
> the destructor of a local variable, although an error will occur later when
> the local variable goes out of scope and is destroyed a second time.
Wow - I did not even know that it was legal C++ to explicitly call a
d'tor, as in:
SomeObject someObject;
someObject.~SomeObject();
(at least my gcc on Mac compiles this without complaint. And as long as
you don't release any resources twice inside the d'tor - or simply have
a qDebug("D'tor called.") or something in the d'tor - nothing bad
happens: the d'tor is indeed simply called twice (once explicitly, once
the automatic variable goes out of scope).
However it never occured to me to actually try such a thing. I mean,
what would be a practical scenario where one wanted to explicitly call a
d'tor? So clean up resources before the actual object gets destroyed
(assuming that the code inside the d'tor would take care not to delete
resources twice, such that it would be okay to call a d'tor several times)?
So when I read something like "...it then calls the destructor of its
child..." my brain automatically transmogrifies this into "... it then
calls delete of its child ...".
But you are right, given the fact that it actually /is/ legal C++ - and
semantically different from calling delete on an object - to explicitly
call a d'tor, the above is not quite right (but I'm 99% sure that what
is really meant here that delete is called upon the child, because
calling a d'tor directly doesn't make any sense to me).
> However, it is not legal to call delete on a local (non-new'ed) variable,
> and the error occurs right when delete is called, rather than later when
> the variable goes out of scope.
Just to be precise: it /is/ legal C++ to call delete on a stack
variable, at least in the syntactical sense:
SomeObject someObject; // allocated on the stack
delete &someObject; // does complain just fine
My gcc on Mac did not even issue a big fat warning with the standard
qmake settings, but not surprisingly above code crashes immediatelly at
that point, just as K. Frank said:
error for object 0x7fff5fbff7cf: pointer being freed was not allocated
> A minor point, but the wording got me analyzing things not quite as
> precisely as I should have.
>
>> On a similar note, don't delete QObject instances manually. Call their
>> deleteLater() member function instead.
>
> Yes, well worth remembering that deleteLater() is available.
I think as a rule of thumb one could say that for objects (and their
children) such as dialogs, Qt collection types and probably most other
Qt classes it is fine to call delete (immediate deallocation), as long
as you allocated (new) them yourself.
Or in other words: you have to be careful (and read the docs) with
objects allocated by Qt itself: sometimes Qt indeed still wants to do
some tasks with those objects after it has "handed them to you for
inspection" when it goes back to the event queue - and then you *need*
to call deleteLater() on them (instead of delete).
One concrete example I know of is the QNetworkReply created inside the
Qt event queue (once a network packet or some other network related
event has happened), passed to your code, and you must call deleteLater
on it:
http://qt-project.org/doc/qt-4.8/qnetworkaccessmanager.html#finished
Then there is one API which explicitly requests that the argument you
have to pass be allocated on the heap, because Qt takes ownership of
that object and deletes it later on (with delete). But I cannot remember
which class that was, I thought also the QNetworkAccessManager, or maybe
somewhere in the multithreading departement...
By the way it can be very useful to call delete on a QObject, even if
that object has a valid parent (which would delete all its children
later on, once that parent gets deleted).
For instance if you allocate a dialog on the heap (*), you typically
pass the window from which that dialog was called as parent (as a side
effect, the dialog is then also centered in the parent window/dialog).
You might think you're done, no delete ever necessary on your side,
because that object has a valid parent which will eventually take care
of it!
Now if that parent happens to be the QMainWindow, the child dialogs
won't get deleted until the very end of the application lifecycle. And
they eat up memory (think "file dialog"). Technically /not/ a memory
leak, as the parent QMainWindow still references them (and deletes them
properly when it gets itself deleted). So you should call delete on
those dialogs (or whatever Qt objects), once the user has made the
decision and pressed either OK or Cancel. As we have seen calling delete
is absolutely fine, because the child will "unregister" itself from its
parent.
Cheers,
Oliver
(*) This very scenario is one reason why people argue you should
allocate (file) dialogs etc. on the stack, such that they automatically
get deallocated when not needed anymore. I won't go into any more
details here, but if you want to indulge yourself with more "heap vs
stack allocation" discussions, go back into the Qt archive, e.g. here:
http://lists.trolltech.com/qt-interest/2007-08/thread00403-0.html
:)
More information about the Interest
mailing list