C ++ / Qt如何 - 内存分配有效?

时间:2010-06-08 20:24:36

标签: c++ qt memory shared-ptr memory-leaks

我最近开始为自己调查Qt并提出以下问题:

假设我有一些QTreeWidget* widget。在某些时候,我想添加一些项目,这可以通过以下调用完成:

QList<QTreeWidgetItem*> items;

// Prepare the items
QTreeWidgetItem* item1 = new QTreeWidgetItem(...);
QTreeWidgetItem* item2 = new QTreeWidgetItem(...);
items.append(item1);
items.append(item2);

widget->addTopLevelItems(items);

到目前为止看起来还不错,但我实际上并不了解谁应该控制对象的生命周期。我应该用示例解释这个:

让我们说,另一个函数调用widget->clear();我不知道在这个调用下发生了什么,但我确实认为为item1和{{1}分配的内存在这里没有被处理,因为它们的实际上并没有被转移。 而且,砰,我们有内存泄漏。

问题如下 - item2是否可以为这种情况提供一些东西?我可以使用Qt或任何其他智能指针并编写类似< / p>

boost::shared_ptr

但我不知道Qt本身是否会尝试对我的指针进行明确的shared_ptr<QTreeWidgetItem> ptr(new QTreeWidgetItem(...)); items.append(ptr.get()); 调用(因为我将它们声明为delete - 托管)会是灾难性的。

你会如何解决这个问题? 也许一切都很明显,我想念一些非常简单的东西?

3 个答案:

答案 0 :(得分:7)

快速查看qtreewidget.cpp显示了这一点:

void QTreeWidget::clear()
{
   Q_D(QTreeWidget);
   selectionModel()->clear();
   d->treeModel()->clear();
}

void QTreeModel::clear()
{
   SkipSorting skipSorting(this);
   for (int i = 0; i < rootItem->childCount(); ++i) {
       QTreeWidgetItem *item = rootItem->children.at(i);
       item->par = 0;
       item->view = 0;
       delete item;     //   <<----- Aha!
   }
   rootItem->children.clear();
   sortPendingTimer.stop();
   reset();
}

所以看来你对widget-&gt; addTopLevelItems()的调用确实会导致QTreeWidget获得QTreeWidgetItems的所有权。所以你不应该自己删除它们,或者将它们保存在shared_ptr中,否则你最终会遇到双删除问题。

答案 1 :(得分:4)

Qt有自己的智能指针,请看http://doc.qt.io/archives/4.6/qsharedpointer.html。通常,尽可能使用Qt的标准所有权层次结构是可取的。这个概念在这里描述: http://doc.qt.io/archives/4.6/objecttrees.html

对于您的具体示例,这意味着您应该将指向容器(即QTreeWidget)的指针传递给子对象的构造函数。每个QWidget子类构造函数都会为此目的获取一个指向QWidget的指针。将子指针传递给容器时,容器将负责清理子容器。这是您需要修改示例的方法:

QTreeWidgetItem* item1 = new QTreeWidgetItem(..., widget);
QTreeWidgetItem* item2 = new QTreeWidgetItem(..., widget);

(我不知道你的例子中有什么......但Qt内存管理的重要内容是最后一个参数)。

使用智能指针的示例

shared_ptr<QTreeWidgetItem> ptr(new QTreeWidgetItem(...));
items.append(ptr.get());

不是一个好主意,因为你打破了智能指针的黄金法则:永远不要直接使用智能指针管理对象的原始指针。

答案 2 :(得分:1)

可以使用父QObject *构造许多Qt类实例。此父级控制构建的子级的生命周期。看看QTreeWidgetItem是否可以链接到父窗口小部件,看起来是这样,阅读Qt docs:

  

项目通常用a构造   父级是QTreeWidget   (对于顶级项目)或a   QTreeWidgetItem(用于较低的项目)   树的水平。)