我有一个充满动态创建的对象的Qlist。在终止我的程序之前,我调用myqlist.clear()
我的问题是:这是否也删除(免费)列表中包含的对象? Valgrind给了我一些丢失的块,我想知道我是否误解了qlist clear方法是如何工作的。
或者,我是否需要遍历qlist并删除每个对象?
更新:我可以确认mylist.erase(迭代器)正在从列表中删除该项,但不释放动态分配的对象。 (该对象是动态实例化的类)。很奇怪!我从Qlist切换到QLinkedList但结果相同。记住,我的QLinkedList是一个QLinkedList< MyClass的>不是QLinkedList< * myclass>
这是实际的代码,以防有人能找到我做错的事情:
// Here I define a couple important items. Note that AMISendMessageFormat is a class
typedef QLinkedList<AMISendMessageFormat> TSentMessageQueue;
TSentMessageQueue m_sentMessageQueue;
// Here I create the message and append to my QLinkedList
AMISendMessageFormat *newMessage = new AMISendMessageFormat(messageToSend);
m_sentMessageQueue.append(*newMessage);
// Here I delete
for (TSentMessageQueue::Iterator sMessagePtr = m_sentMessageQueue.begin(); sMessagePtr != m_sentMessageQueue.end(); )
{
sMessagePtr = m_sentMessageQueue.erase(sMessagePtr);
qDebug() << "Sent size after erase: " << m_sentMessageQueue.size(); // Confirmed linked list is shrinking in size
}
在遍历列表并擦除之后,valgrind显示每个AMISendMessageFormat对象都是丢失的块!
我怀疑这与使用迭代器在循环内擦除有关...但我无法理解这个问题!
请参阅下面的详细解决方案...问题是,追加功能会复制并将其添加到列表中...我虽然是添加实际对象(不是副本)...所以问题是'新的副本被泄露了。
答案 0 :(得分:5)
您正在泄漏newMessage
指向的实例。这与列表无关!你没有从列表中泄露出来。解决方案:
// Best
m_sentMessageQueue << AMISendMessageFormat(messageToSend);
// Same, more writing
AMISendMessageFormat newMessage(messageToSend);
m_sentMessageQueue << newMessage;
// Rather pointless allocation on the heap
QScopedPointer<AMISendMessageFormat> newMessage(new AMISendMessageFormat(messageToSend));
m_sentMessageQueue << *newMessage;
请注意,在每种情况下,您都将对象的副本存储到列表中。 重要:您必须验证AMISendMessageFormat
是否是一个正确运行的C ++类,可以安全地复制构造并分配给它而不会泄漏资源。
如果您没有定义复制构造函数和赋值运算符,那么您在此类中使用的所有数据成员必须可以安全地复制和分配,而不会泄漏。所有Qt和C ++标准库类都不会在这种用途下编译或者行为正常。如果你正在使用裸指针,那么你已经用脚射击了自己,所以至少要使用正确的QSharedPointer
。
在编辑之前,你没有说出你的对象是什么。
如果要在列表中存储原始指针,那么在执行clear()
时肯定会泄漏内存。 QList
将这些指针视为整数,并且不会对它们做任何特殊处理。在C ++中,破坏原始指针就像破坏整数一样,是NO-OP。
如果您在列表中存储QSharedPointer
或std::shared_ptr
,则执行clear()
时不会泄漏内存。出于某种原因,智能指针被称为:)
如果您自己存储对象,并且它们是正确运行的C ++类,那么一切都很好。
您无法将QObject
直接存储在QList
中,因此您的“对象”不能 QObjects - 它无法编译。
这种方法很好并且行为正常:
QList<QString> stringList1;
QList<QSharedPointer<QString> > stringList2;
stringList1 << "Foo" << "Bar" << "Baz";
stringList2 << new QString("Foo") << new QString("Bar") << new QString("Baz");
Q_ASSERT(stringList1.at(0) == *stringList2.at(0));
stringList1.clear();
stringList2.clear(); // no memory leaks
这会泄漏内存,你几乎不需要编写这样的代码:
QList<QString*> stringList3;
stringList3 << new QString("Foo") << new QString("Bar") << new QString("Baz");
stringList3.clear();
另请注意,QList
和所有不错的C ++容器类型都是RAII。这意味着他们将释放他们在销毁时使用的资源。这意味着您不需要在列表上调用clear()
,除非您确实要清除列表。此代码不会泄漏资源。列表的析构函数将在main()
返回之前被调用,列表的析构函数将破坏所有字符串,并且它们都将正确释放它们分配的堆内存。
int main() {
QList<QString> stringList1;
stringList1 << "Foo" << "Bar" << "Baz";
return 0;
}
答案 1 :(得分:3)
qDeleteAll(list.begin(), list.end());
答案 2 :(得分:0)
这取决于您的对象。 Qt有一个object ownership的概念,它在树中组织对象。树的父节点一旦超出范围就会删除它的所有子节点。
如果您的对象不是由父对象管理,则需要确保自己解除分配。 Qt还附带了一组smart pointers来简化这一过程。