2017-08-24 39 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()并没有真正检查指针的有效性:如果指针已被删除,这样的调用只会产生未定义的行为 - 应用程序可能会崩溃,或者可能不会。