Thursday, November 22, 2007

Memory Leak Continued

There was some confusion with regard to my last blog about leaking memory. Suppose the ui_mywidget.h files looks like this:
class Ui_Widget
{
public:
QGridLayout *gridLayout;
QGroupBox *groupBox;
QGridLayout *gridLayout1;
QListWidget *listWidget;
QSpacerItem *spacerItem;
QPushButton *pushButton;

void setupUi(QWidget *Widget);
void retranslateUi(QWidget *Widget);
};
Of course, those 6 QObject derived classes are deleted. But the sizeof(Ui_Widget) = 6 * sizeof(void*) = 24 bytes are not deleted. As Ui_Widget is not QObject derived those 24 bytes leak. Confirmed by valgrind.

In a comment to my last blog Paolo suggested to use auto_ptr or scoped_ptr, which is more elegant than an extra wrapper class :)

Wednesday, November 21, 2007

Memory leak: Ui files and direct approach

The KDE codebase often uses a forward declaration in the .h-file to speedup compilation. The code often looks like this:
// header file
namespace Ui { class MyWidget; }
class MyDialog : public KDialog {
// ...
private:
Ui::MyWidget *ui;
};
The impl looks like this:
// source file
#include "mydialog.h"
#include "ui_mywidget.h"
MyDialog::MyDialog() : KDialog()
{
QWidget *w = new QWidget(this);
setMainWidget(w);
ui = new Ui::MyWidget(); // allocation
ui->setupUi(w);
// ui->...
}
See the memory leak? You have to call »delete ui;« in the destructor if you use the »direct approach«. Searching in lxr.kde.org shows lots of results, and in some places this delete is missing indeed. Happy fixing :)


Update: The really correct fix is to guard the pointer with an auto_ptr or scoped_ptr. For further details read the comments below. Or use another approach to include your ui-file.


If you do not want to delete it manually, you can for instance use a workaround like this:
// header file
namespace Ui { class MyWidget; }
class MyWidget;
class MyDialog : public KDialog {
// ...
private:
Ui::MyWidget *ui;
};
Source file:
// source file
#include "mydialog.h"
#include "ui_mywidget.h"

class MyWidget : public QWidget, public Ui::MyWidget {
public:
MyWidget( QWidget * parent = 0 ) : QWidget( parent )
{ setupUi(this); }
};

MyDialog::MyDialog() : KDialog()
{
ui = new MyWidget(this);
setMainWidget(ui);
QWidget *w = new QWidget(this);
setMainWidget(w);
ui = new Ui::MyDialog(); // allocation
ui->setupUi(w);
// ui->...
}