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

Я очень запутался в использовании деструкторов в 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()?

Ответ 1

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

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

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

Ответ 2

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

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

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

Qt не предоставляет дополнительных гарантий, кроме стандартного С++, если вы не используете 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
}

Ответ 3

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

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

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

Ответ 4

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

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

Ответ 5

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

    QPushButton push("neu");

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