需要释放QList内容吗?

时间:2014-01-27 16:35:08

标签: c++ qt memory delete-operator qlist

我有一个充满动态创建的对象的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对象都是丢失的块!

我怀疑这与使用迭代器在循环内擦除有关...但我无法理解这个问题!


请参阅下面的详细解决方案...问题是,追加功能会复制并将其添加到列表中...我虽然是添加实际对象(不是副本)...所以问题是'新的副本被泄露了。

3 个答案:

答案 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。

  • 如果您在列表中存储QSharedPointerstd::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来简化这一过程。