деструкторы в Qt4 - PullRequest
       38

деструкторы в Qt4

11 голосов
/ 17 сентября 2009

Я очень озадачен использованием деструкторов в Qt4 и надеюсь, вы, ребята, можете мне помочь.
Когда у меня есть такой метод (с "Des" это класс):

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

как я могу убедиться, что этот виджет будет удален после его закрытия?

А в классе "Des" у меня есть это:

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

где и как мне удалить * push и * layout? что должно быть в деструкторе Des :: ~ Des ()?

Ответы [ 5 ]

21 голосов
/ 17 сентября 2009

Qt использует то, что они называют деревьями , и это немного отличается от типичного подхода RAII.

Конструктор QObject class принимает указатель на родителя QObject. Когда этот родитель QObject будет уничтожен, его дети также будут уничтожены. Это довольно распространенный шаблон в классах Qt, и вы заметите, что многие конструкторы принимают параметр *parent.

Если вы посмотрите на некоторые из примеров программ Qt , вы обнаружите, что они фактически создают большинство объектов Qt в куче и используют это дерево объектов для обработки уничтожения. Лично я нашел эту стратегию полезной, поскольку объекты GUI могут иметь своеобразное время жизни.

Qt не предоставляет никаких дополнительных гарантий помимо стандартного C ++, если вы не используете QObject или подкласс QObject (например, QWidget).


В вашем конкретном примере нет гарантии, что что-либо будет удалено.

Вы захотите что-то подобное для Des (при условии, что Des является подклассом 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
    }
}

И вы бы использовали класс Des примерно так:

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
}
12 голосов
/ 17 сентября 2009

Другой вариант использования deleteLater() или его родителей - использовать функцию удаления при закрытии для виджетов. В этом случае Qt удалит виджет, когда он будет отображен.

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

Мне нравится использовать его с деревом объектов, которое хранит Qt, так что я установил delete-on-close для окна, и у всех виджетов в окне был указан правильный родительский элемент, так что все они также будут удалены. 1005 *

5 голосов
/ 17 сентября 2009

Хороший ответ Ричардба - но другой подход заключается в использовании слота deleteLater, например, так:

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

Очевидно, что сигнал closed () можно заменить любым сигналом, который вы хотите.

3 голосов
/ 17 сентября 2009

В этом руководстве предполагается, что вам не нужно явно удалять виджеты, которые были добавлены в родительские виджеты. Он также говорит, что не мешает удалить их тоже.

(Я не проверял это, но я думаю, если вы явно удалите их до удаления родительского виджета, это должно быть в порядке.)

2 голосов
/ 17 сентября 2009

В большинстве случаев вы должны создавать виджеты в стеке:

    QPushButton push("neu");

Таким образом, они удаляются, когда выходят из области видимости. Если вы действительно хотите создать их в куче, то вы обязаны вызывать их, когда они больше не нужны.

...