kde-extraapps/amarok/HACKING/memory_management_tips.txt
2015-01-31 00:30:50 +00:00

117 lines
3.3 KiB
Text

TIPS FOR CORRECT MEMORY MANAGEMENT WITH C++ AND QT
==================================================
1)
Use of "Smart Pointers":
A smart pointer in C++ means (in its most simple incarnation) a
pointer that automatically sets itself to 0, when the object it points
to is being destroyed (deleted).
Advantages:
No risk of "dangling pointers". A dangling pointer is a pointer that
has been deleted, but still contains the memory address of the object
that has been destroyed. What happens if you delete this again is
called a "double-free", and almost always leads to a crash. With a
smart pointer, you can delete the object safely again, because
deleting a 0-pointer is defined as a safe (doing nothing) operation in
the C++ standard.
Example:
WRONG:
QWidget* foo = new QWidget();
delete foo;
delete foo;
<BOOOOM>
RIGHT:
QPointer<QWidget> foo = new QWidget();
delete foo;
delete foo;
<not nice, but no crash>
2)
Always make sure not to dereference a 0-pointer:
This is _the_ single most common crash cause in Amarok 2 currently.
It's easy to prevent, but unfortunately also easy to miss:
Example:
WRONG:
Meta::TrackPtr foo;
debug() << foo->prettyUrl();
<BOOOOM>
RIGHT:
Meta::TrackPtr foo;
if( foo )
debug() << foo->prettyUrl();
<no output, and no crash>
Also be aware that Amarok is multi-threaded. So somebody could
change pointers while you are looking away like here:
WRONG:
Meta::TrackPtr myTrack;
if( myTrack && myTrack->album() )
debug() << myTrack->album()->name();
<somebody could set the album to 0 just after the if>
RIGHT:
Meta::TrackPtr myTrack;
Meta::AlbumPtr myAlbum = myTrack ? myTrack->album() : 0;
if( myAlbum )
debug() << myAlbum->name();
3)
Private d-pointer classes can be used in cases where the interfaces
of a library should remain stable but the size of members and their
inner working should change.
Qt is doing it. KDE is doing it. We are also doing it in some places
for no apparent reason and no benefit.
However, if you are doing it, never, ever, use private d-pointer
classes in QObject derived subclasses:
What can happen is that you do a "delete d;" in your destructor, and
then Qt goes ahead and auto-deletes other QObject pointers contained
in the private class again, through means of its automatic deleting of
QObjects with a parent Object. -> <BOOOOM>
Read more about this topic in Michael Pyne's interesting blog article:
http://www.purinchu.net/wp/2009/02/04/another-programming-tidbit/
4)
Use Valgrind:
<Ralf disagrees. Larger projects with big libraries will have so
many dirty places that Valgrind reports too many issues.
Our own way of handling singleton objects does not help. They
just leak. Instead have a sharp look at all your instance variables.
Ensure that all are initialized in the constructor and all deleted
in the destructor.>
This is one of the most advanced memory debugging tools available,
it's free, and we even have found volunteers that run regular Valgrind
checks (both for memory access bugs and memory leaks) on Amarok trunk.
Reading the Valgrind logs correctly is a bit of an art in itself, but
I'm willing to explain this in another posting, if there is a demand.
Recommended reading on the topic of memory management is this page of
the excellent "C++ FAQ Lite":
http://www.parashift.com/c++-faq-lite/freestore-mgmt.html