destructors in Qt4

13,063

Solution 1

Another option to using deleteLater(), or parents, is to use the delete-on-close functionality for widgets. In this case, Qt will delete the widget when it is done being displayed.

Des *test = new Des;
test->setAttribute( Qt::WA_DeleteOnClose );
test->show();

I like to use it with the object tree that Qt keeps, so that I set delete-on-close for the window, and all widgets in the window have a proper parent specified, so they all get deleted as well.

Solution 2

Qt uses what they call object trees and it's a bit different from the typical RAII approach.

The QObject class constructor takes a pointer to a parent QObject. When that parent QObject is destructed, its children will be destroyed as well. This is a pretty prevalent pattern throughout Qt's classes and you'll notice a lot of constructors accept a *parent parameter.

If you look at some of the Qt example programs you'll find that they actually construct most Qt objects on the heap and take advantage of this object tree to handle destruction. I personally found this strategy useful as well, as GUI objects can have peculiar lifetimes.

Qt provides no additional guarantees beyond standard C++ if you're not using QObject or a subclass of QObject (such as QWidget).


In your particular example there's no guarantee that anything gets deleted.

You'll want something like this for Des (assuming Des is a subclass of QWidget):

class Des : public QWidget
{
    Q_OBJECT

public:
    Des(QWidget* parent)
    : QWidget(parent)
    {
        QPushButton* push = new QPushButton("neu");
        QHBoxLayout* layout = new QHBoxLayout(this);
        layout->addWidget(push); // this re-parents push so layout 
                                 // is the parent of push
        setLayout(layout);
    }

    ~Des()
    {
        // empty, since when Des is destroyed, all its children (in Qt terms)
        // will be destroyed as well
    }
}

And you'd use class Des like so:

int someFunction()
{
    // on the heap
    Des* test = new Des(parent); // where parent is a QWidget*
    test->show();
    ...
    // test will be destroyed when its parent is destroyed

    // or on the stack
    Des foo(0);
    foo.show();
    ...
    // foo will fall out of scope and get deleted
}

Solution 3

Richardwb's answer is a good one - but the other approach is to use the deleteLater slot, like so:

Des *test = new Des;
test->show();
connect(test, SIGNAL(closed()), test, SLOT(deleteLater()));

Obviously the closed() signal can be replaced with whatever signal you want.

Solution 4

This tutorial suggests you don't need to explicitly delete widgets that have been added to parent widgets. It also says it doesn't hurt to do delete them either.

(I've not tested this, but I guess as long as you explicitly delete them before the parent widget is deleted, this should be OK.)

Solution 5

In most cases you should create widgets on the stack:

    QPushButton push("neu");

This way, they get deleted when they become out of scope. If you really want to create them on the heap, then it's your responsibility to call delete on them when they are not needed anymore.

Share:
13,063
Berschi
Author by

Berschi

Updated on June 17, 2022

Comments

  • Berschi
    Berschi almost 2 years

    I'm very confused about using destructors in Qt4 and hope, you guys can help me.
    When I have a method like this (with "Des" is a class):

    void Widget::create() {
        Des *test = new Des;
        test->show();
    }
    

    how can I make sure that this widget is going to be deleted after it was closed?

    And in class "Des" i have this:

    Des::Des()
    {
        QPushButton *push = new QPushButton("neu");
        QHBoxLayout *layout = new QHBoxLayout;
        layout->addWidget(push);
        setLayout(layout);
    }
    

    where and how do I have to delete *push and *layout? what should be in the destructor Des::~Des() ?

  • David Rodríguez - dribeas
    David Rodríguez - dribeas over 14 years
    It is a little more complex than that. QT will trigger the destruction of some objects in some situations (if they are registered with a parent) and thus, having them stack allocated would kill the application with a double free.
  • David Rodríguez - dribeas
    David Rodríguez - dribeas over 14 years
    +1, but trying to delete them after the parent widget has been deleted ends up with a double delete and the application dying.
  • rpg
    rpg over 14 years
    dribeas, I think that when a QObject is destructed it is automatically unregistered from the parent.
  • static_rtti
    static_rtti over 14 years
    I use stack allocation with QObjects all the time and it works fine. Thanks for the uninformed downmod.
  • Berschi
    Berschi over 14 years
    there is no SIGNAL(closed()) for this widget. SIGNALS are: customContextMenuRequested(QPoint), destroyed() and destroyed(QObject*)
  • Berschi
    Berschi over 14 years
    this seems to work very good. thanks. But when I create 4 new "test"-widgets for example and close them again, creating another "test"-widget will not cost more memory, but the application still uses as much as memory as when the 4 "test"-widgets still would exist. Is that normal?
  • Caleb Huitt - cjhuitt
    Caleb Huitt - cjhuitt over 14 years
    @Berschi, it is possible that either Qt or your OS is doing some memory optimization. If the fifth widget you mention in your comment causes no more memory to be used, I wouldn't worry about it too much. Another option, if you are concerned, is to find a tool like valgrind and run your program through it.
  • richardwb
    richardwb over 14 years
    If the widget doesn't have a clean lifetime and no parents with which to associate it with, the best option is to use the delete-on-close functionality that cjhuitt mentions in another answer.
  • Thomi
    Thomi over 14 years
    OK, well, it was meant as a general concept, rather than a concrete example. Maybe you can add a signal that gets emitted when your object finishes it's work? It's a useful pattern anyway, it lets you create something and forget about it, provided that you don't store any references to it, and that it does, eventually finish.
  • Naruto
    Naruto about 14 years
    just for the clarification, if we make the "Pushbutton" as member variable, then do we need to delete the push-button manually at the widget destructor or it will gets deleted when the parent gets deleted..
  • richardwb
    richardwb about 14 years
    If you have a QPushButton * as a member variable and give it a suitable parent (with its constructor or with setParent()) it will be deleted when the parent is deleted. You could also use a plain QPushButton (and let the standard C++ destruction rules kick in), but you'll probably find that for a lot of the Qt GUI stuff you'll want a parent anyway.
  • BetweenTwoTests
    BetweenTwoTests almost 14 years
    @rpg: Yes, the point is, that the parent must not be deleted when the child exists, or you have to ensure the parent doesn't hold ownership.