PDA

View Full Version : Parent deleting children in a derived class



giblit
4th March 2014, 02:52
Say we have a custom Widget that looks something along the lines of:



class Test : public QWidget
{
public:
Test(QWidget *parent = nullptr) : QWidget(parent) , label(new QLabel(tr("Hello")))
{
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget( label );
setLayout( layout ); //add the current layout and widgets to be children to this(Test)
}
~Test(void){}
private:
QLabel *label;
};


What I am concerned about is memory leaking from label or layout when I delete a parent (Test) object. I tried something like:
~Test( void ) { if( label ) std::cerr << "Label was not destroyed!" << std::endl; } and the output was not what I was hoping for could this be due to me mistaking what they mean by being a parent/child or does it delete them in some random order?

Also when we have nested layouts and we destroy the parent layout are the children layouts automatically deleted also?

Something like:



QHBoxLayout *layout1 = new QHBoxLayout;
QVBoxLayout *layout2 = new QVBoxLayout;
layout2->addLayout(layout1);

//if layout2 is deleted is layout1 also?

I am used to having to manually delete heap stuff or the use of RAII not the object tree way. Thanks for any help I greatly appreciate it. :)

ChrisW67
4th March 2014, 03:40
The child objects will be deleted when the QObject destructor runs, which will occur after the derived class destructor does. The children are directly deleted at that time, i.e. QObject::deleteLater() is not used. At the point you inspect the value of label it has not been destroyed. (Deleting the label would not reset the value of the pointer to 0 in any case, so your test is not a good one.)

A child layout added to another layout is given the parent layout as its parent. Widgets that layouts control are parented to the widget that the top-most layout is associated with. They typically are all destroyed automatically when the owning widget is destroyed.

Inspect the output of this to see the order of things


#include <QApplication>
#include <QVBoxLayout>
#include <QWidget>
#include <QTimer>
#include <QDebug>

class InstrumentedWidget: public QWidget
{
Q_OBJECT
public:
InstrumentedWidget(QWidget *p = 0): QWidget(p) {
qDebug() << "Construct" << this;
}
~InstrumentedWidget() {
qDebug() << "Destroy" << this << this->parent();
}
};

class InstrumentedVBox: public QVBoxLayout
{
Q_OBJECT
public:
InstrumentedVBox(QWidget *p = 0): QVBoxLayout(p) {
qDebug() << "Construct" << this;
}
~InstrumentedVBox() {
qDebug() << "Destroy" << this << this->parent();
}
};

int main(int argc, char **argv) {
QApplication app(argc, argv);

InstrumentedWidget mw;

InstrumentedVBox *outer = new InstrumentedVBox;
outer->addWidget(new InstrumentedWidget);
outer->addWidget(new InstrumentedWidget);

InstrumentedVBox *inner = new InstrumentedVBox;
inner->addWidget(new InstrumentedWidget);
inner->addWidget(new InstrumentedWidget);
outer->addLayout(inner);

mw.setLayout(outer);

qDebug() << "Waiting a second";
QTimer::singleShot(1000, &app, SLOT(quit()));
return app.exec();
// mw will be destroyed here
}
#include "main.moc"

giblit
4th March 2014, 04:09
Deleting the label would not reset the value of the pointer to 0 in any case, so your test is not a good one.
Was thinking that the QObject destructor would delete it then assign it as a nullptr for some odd reason.

Thanks for your example I see how it works now. It just felt weird creating objects on the heap without RAII and them being deleted automatically.

Lesiok
4th March 2014, 06:57
If You want to auto-reset pointer after object deleting use QPointer. From QPointer doc : A guarded pointer, QPointer<T>, behaves like a normal C++ pointer T *, except that it is automatically set to 0 when the referenced object is destroyed (unlike normal C++ pointers, which become "dangling pointers" in such cases)

giblit
4th March 2014, 19:28
Thanks. I didn't know that.