2017-08-24 71 views
0

我在試圖刪除QTreeWidgetItem的代碼中遇到一個奇怪的問題。特別是,我有這個在我的課:SegFault刪除QTreeWidgetItem

std::map<int, std::unique_ptr<QTreeWidgetItem>> mymap; 

當我關閉應用程序,我有段錯誤,該unique_ptr的默認析構函數中。於是,我嘗試將問題分解,和我創建一個析構函數執行以下操作:

~MyClass() { 
    for (auto x = mymap.begin(); x != mymap.end(); x++ ) { 
     QTreeWidgetItem* temp = x->second.release(); 
     qDebug() << "make sure the pointer is not broken " << temp->isDisabled(); 
     delete temp; 
    } 
} 

的調用函數isDisabled()是沒用的,只是爲了確保指針不破。那麼,我可以使用指針中的對象,但是當我嘗試刪除它時,我有SegFault。

有什麼建議嗎?感謝大家

+0

爲什麼你需要首先將'QTreeWidgetItems'作爲'unique_ptrs'存儲? 'QTreeWidgetItem'被設計成具有'QTreeWidget'作爲它的父項,因此這個父窗口小部件將負責在合適的時候刪除這些項目。在你的情況下最有可能發生的事情是雙重免費的,因爲樹零件項的兩個所有者:'QTreeWidget'和'unique_ptr'。確保你瞭解Qt的[親子關係和內存管理](http://doc.qt.io/qt-5/objecttrees.html)。 – Dmitry

+0

Hi @Dmitry,感謝您的評論。那麼我明白這個用法可能會很奇怪,但它應該起作用。在[doc](http://doc.qt.io/qt-5/qtreewidgetitem.html)中,QTreeWidgetItem不是'QObject'。無論如何,在你的鏈接中,它被寫爲「當在堆上創建QObject時(即用新創建的),可以以任意順序從它們構建一棵樹,隨後樹中的對象可以在任何訂單「,我使用'new'來創建它。最後,在這種情況下,我期望Qt嘗試刪除父項時使用SegFault,但不會在我的行'delete temp'中。我是否犯了一些錯誤? – n3mo

+0

確實,'QTreeWidgetItem'不是'QObject',但類似的原理適用於'QTreeWidget'和'QTreeWidgetItem'。 'QTreeWidget'的析構函數[doc](https://doc.qt.io/qt-5/qtreewidget.html#dtor.QTreeWidget)表示它「銷燬了樹部件及其所有項目」。爲什麼segfault發生在'delete temp'上很難說。檢查「QTreeWidget」在那一刻是否還活着。如果不是,你正在做同樣的指針的第二次刪除,因此崩潰。調用'temp-> isDisabled()'什麼都不檢查:如果它已經被刪除,它只是未定義的行爲 - 它可能會崩潰或者它可能不會。 – Dmitry

回答

1

QTreeWidgetItems被設計爲擁有QTreeWidget。正如documentation所說,在QTreeWidget的析構函數中,其所有項目都被刪除。在QTreeWidget中存在std::unique_ptrQTreeWidgetItem創建了QTreeWidgetItem的第二個獨立所有權,因此導致相同指針的雙重刪除。在你的例子中發生了崩潰,因爲在手動刪除的時候,指針已經被刪除,QTreeWidget持有它。

調用temp->isDisabled()並沒有真正檢查指針的有效性:如果指針已被刪除,這樣的調用只會產生未定義的行爲 - 應用程序可能會崩潰,或者可能不會。