Я недавно начал исследовать 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
и item2
не становится склонным здесь, потому что их ownage не был на самом деле передан. И, удар, у нас есть утечка памяти.
Вопрос следующий - делает Qt
что-то имеет для предложения для этого вида ситуации? Я мог использовать boost::shared_ptr
или любой другой интеллектуальный указатель и запись что-то как
shared_ptr<QTreeWidgetItem> ptr(new QTreeWidgetItem(...));
items.append(ptr.get());
но я не знаю, попытался ли сам QT сделать явным delete
запросы к моим указателям (который имел бы катастрофические последствия, так как я заявляю им как shared_ptr
- управляемый).
Как Вы решили бы эту проблему? Возможно, все очевидно, и я пропускаю что-то действительно простое?
Беглый взгляд на 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-> addTopLevelItems () действительно заставляет QTreeWidget стать владельцем QTreeWidgetItems. Таким образом, вы не должны удалять их самостоятельно или хранить их в shared_ptr, иначе вы столкнетесь с проблемой двойного удаления.
В 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());
- не очень хорошая идея, потому что вы нарушаете золотое правило умных указателей: Никогда не используйте необработанный указатель объекта, управляемого умным указателем, напрямую.
Многие экземпляры классов Qt могут быть построены с родительским QObject*. Этот родитель контролирует время жизни построенного дочернего объекта. Посмотрите, может ли QTreeWidgetItem быть связан с родительским виджетом, похоже, что да, читая документацию Qt:
Элементы обычно конструируются с родителем, который является либо QTreeWidget (для элементов верхнего уровня) или QTreeWidgetItem (для элементов на более низких уровнях дерева).