2009-09-17 49 views
11

对于在Qt4中使用析构函数我很困惑,希望你们能帮助我。
当我有这样的方法(以“德”是一个类):Qt4中的析构函数

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

我怎么能保证这个小部件会被关闭后删除?

在课堂上“梅”我有这样的:

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

哪里?我怎么也删除*推动和*布局? Des ::〜Des()中应该包含什么?

回答

12

另一种选择使用deleteLater(),或者父母,是使用小工具删除 - 在关闭功能。在这种情况下,Qt将在完成显示时删除该小部件。

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

我喜欢与Qt的保留,所以我设置删除,在关闭该窗口的对象树使用它,并在窗口中的所有部件都指定一个适当的父母,所以他们都被删除以及。

+0

这似乎工作得很好。谢谢。 但是,当我创建例如4个新的“测试” -widgets并再次关闭它们,创建另一个“测试” -widget不会花费更多的内存,但是应用程序仍然使用尽可能多的内存作为当4“测试” -widgets仍然会存在。这是正常的吗? – Berschi 2009-09-17 14:54:46

+1

@Berschi,Qt或您的操作系统可能会进行一些内存优化。如果你在评论中提到的第五个小部件导致没有更多的内存被使用,我不会担心它太多。如果您担心,另一种选择是找到像valgrind这样的工具并通过它运行您的程序。 – 2009-09-17 22:45:33

2

在大多数情况下,你应该在栈上创建的小部件:

QPushButton push("neu"); 

这样,当他们成为了其作用范围时被删除。如果你真的想在堆上创建它们,那么你有责任在它们不再需要时调用它们的删除。

+1

这比这更复杂一点。 QT会在某些情况下触发某些对象的销毁(如果它们是向父级注册的),因此,让它们分配堆栈会使应用程序失去双重空间。 – 2009-09-17 06:10:44

+3

dribeas,我认为当一个QObject被破坏时,它会自动从父类注销。 – rpg 2009-09-17 09:18:10

+1

我一直使用QObjects的堆栈分配,它工作正常。感谢不知情的downmod。 – 2009-09-17 11:23:04

3

This tutorial建议您不需要显式删除已添加到父窗口小部件的窗口小部件。它还表示,删除它们也不会造成伤害。

(我没有测试过这一点,但我想只要你明确地删除它们被删除父控件之前,这个应该没问题。)

+2

+1,但试图删除它们后_父窗口小部件已被删除结束与双删除和应用程序死亡。 – 2009-09-17 06:11:50

21

Qt使用他们称之为object trees,这是一个有点不同从典型的RAII方法。

QObjectconstructor需要一个父指针QObject。当父母QObject遭到破坏时,其子女也将被销毁。这是整个Qt类中相当普遍的模式,您会注意到很多构造函数接受*parent参数。

如果你看一些Qt example programs,你会发现他们实际上在堆上构建了大多数Qt对象,并利用这个对象树来处理破坏。我个人发现这个策略也很有用,因为GUI对象可能具有特殊的生命周期。

如果您不使用QObjectQObject(如QWidget)的子类,则Qt不会提供超出标准C++的额外保证。


在您的特定示例中,不保证会删除任何内容。

你会想是这样的Des(假设DesQWidget一个子类):

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 
} 
+0

确定这是非常有帮助的,但我有一个额外的问题: 当我正好接近这个小部件称为“测试”,这并不意味着它也将被销毁,不是吗?我必须为自己销毁/删除它。我该怎么做呢? – Berschi 2009-09-17 14:15:25

+2

如果小部件没有干净的生命周期,并且没有与之关联的父母,最好的选择是使用cjhuitt在另一个答案中提到的delete-on-close功能。 – richardwb 2009-09-18 06:54:37

+0

只是为了澄清,如果能让“按钮”的成员变量,那么我们需要在小部件析构函数手动删除按钮或当父被删除,将被删除.. – Naruto 2010-03-24 11:28:14

5

Richardwb的答案是一个很好的 - 但另一种方法是使用deleteLater插槽,就像这样:

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

很明显,closed()信号可以用任何你想要的信号来代替。

+0

这个小部件没有SIGNAL(关闭())。信号是:customContextMenuRequested(QPoint),破坏()和销毁(QObject的*) – Berschi 2009-09-17 14:22:41

+0

OK,好了,它被认为是一个笼统的概念,而不是一个具体的例子。也许你可以添加一个信号,当你的对象完成它的工作时发出?无论如何,这是一个有用的模式,它可以让你创建一些东西而忘记它,只要你不存储任何对它的引用,并且它确实完成了。 – Thomi 2009-09-18 07:26:27