2011-07-14 88 views
2

我是Qt的新手。所以我開始重新實現其中一個入門示例:link爲什麼此QT應用程序以SIGABRT信號退出?

但是,當關閉窗口時,我得到一個SIGABRT信號。造成這種情況的原因很明顯是由於一些內存管理錯誤。

下面你會找到callstack和相關的代碼。行editWindow.setLayout(&layout);導致錯誤。佈局類是否在銷燬時刪除小部件,因此聲稱擁有它們?

這種行爲的重要性是什麼?以及如何解決它?

此致敬禮。

信息
調用堆棧
callstack

QPushButton testButton("Test"); 

    QVBoxLayout layout; 
    layout.addWidget(&testButton); 

    QWidget editWindow; 
    // the following line is the source of the error 
    editWindow.setLayout(&layout); 
    editWindow.show(); 

    int val = app.exec(); 

回答

7

許多不同的Qt函數將對象的所有權被傳遞,這意味着它假定控制所有的內存管理,並會釋放它在刪除。來自setLayout文檔:

QWidget將取得佈局的所有權。

在調用setLayout之後,它有一個父代,並且它的父代會在清除方法堆棧時將其刪除,並將其刪除。因此,它被刪除了兩次,這導致了問題。

如果一切是正確的,這種變化應該修復它:

QVBoxLayout *layout = new QVBoxLayout(); 
//... 
layout->addWidget(&testButton); 
//... 
editWindow.setLayout(layout); 

另外請注意,這是典型的創造主窗口部件,然後分配將在該控件作爲父顯示部件。換句話說,我期望更像下面的內容(儘管不是絕對必要的)。這也有助於保證,如果有任何在未來得到重設父,你不會有問題:

QWidget editWindow; 
QVBoxLayout *layout = new QVBoxLayout(); 
QPushButton *testButton = new QPushButton(&editWindow); 
layout->addWidget(testButton); 
editWindow.setLayout(layout); 
editWindow.show(); 
int val = app.exec(); 

大多數的Qt被重設父對象和其所有權變更可能發生都會有一個接受QWidget*QObject*構造。

+0

非常感謝你的回答。 – Velrok

2

QWidget希望通過運營商新創建的佈局實例,並採取實例的所有權,要求刪除它時, QWidget被銷燬(see documentation)。因此,你需要的是這樣的:

QVBoxLayout *layout = new QVBoxLayout(); 
/// ... 
editWindow.setLayout(layout); 

的擁有同樣的道理也適用於你的testButton。

+0

佈局沒有取得按鈕的所有權,所以部分應該沒問題......但是,你必須小心,不要做一些事情,重新部署並控制其清理。 –

+0

根據文檔,佈局的addWidget方法使用內部的addItem,它接受所傳遞實例的所有權,請參閱[documentation](http://doc.qt.nokia.com/4.7/qlayout.html#addItem)。 – mike

+0

該文檔實際上說:「**項**的所有權轉移到佈局」,item是由函數參數定義的'QLayoutItem',而不是傳遞給'addWidget'的QWidget。雖然我從來沒有明確地測試過這個,但我從未見過與此相反的事情。如果你測試和發現,請讓我知道。 –

1

示例代碼似乎是錯誤的(奇怪的是)。 QWidget的析構函數在其佈局上調用delete。在你的情況下,QVBoxLayout實例已經在堆棧上而不是在堆上創建,所以在該指針上調用delete無效將中止應用程序。

QObject的所有孩子也一樣。當QObject被刪除時,它會在其所有子級上調用delete,如果這些子級已在堆棧上創建,則它將以相同的方式失敗。

現在明白爲什麼諾基亞發佈的這樣一個壞榜樣......

相關問題