2009-09-17 52 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