我有一个充满动态创建对象的 Qlist。在终止程序之前,我调用 myqlist.clear()
我的问题是:这是否也会删除(释放)列表中包含的对象? Valgrind 给了我一些丢失的 block ,我想知道我是否误解了 qlist clear 方法的工作原理。
或者,我是否需要遍历 qlist 并删除每个对象?
更新:我可以确认 mylist.erase(iterator) 正在从列表中删除项目,但不会释放动态分配的对象。 (该对象是一个动态实例化的类)。很奇怪!我从 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 对象都是丢失的 block !
我怀疑这与使用迭代器在循环内删除有关...但我无法理解这个问题!
请参阅下面的详细解决方案...问题是追加函数制作了一个拷贝并将其添加到列表中...我虽然它添加的是实际对象(而不是拷贝)...所以问题是'新的拷贝被泄露。
最佳答案
您正在泄漏 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
中,因此您的“对象”不能 QObject - 它不会编译。
这工作得很好并且行为正常:
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;
}
关于c++ - 需要释放 QList 内容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21386296/