TSG*_*TSG 5 c++ memory qt qlist delete-operator
我有一个充满动态创建对象的Qlist。在终止程序之前,我先调用myqlist.clear()
我的问题是:这还会删除(释放)列表中包含的对象吗?Valgrind给了我一些丢失的块,我想知道我是否误解了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
}
Run Code Online (Sandbox Code Playgroud)
在遍历列表并擦除之后,valgrind显示每个AMISendMessageFormat对象都是丢失的块!
我怀疑这与用迭代器在循环内擦除有关...但是我无法解决这个问题!
请参阅下面的详细解决方案...问题是append函数会创建一个副本并将其添加到列表中...尽管我正在添加实际对象(而非副本)...所以问题出在“新”副本上被泄漏了。
您正在泄漏指向的实例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;
Run Code Online (Sandbox Code Playgroud)
请注意,在每种情况下,都是将对象的副本存储到列表中。重要说明:您必须验证它AMISendMessageFormat是行为正确的C ++类,可以安全地进行复制构造和分配给它,而不会泄漏资源。
如果您没有定义复制构造函数和赋值运算符,那么您在此类中使用的所有数据成员都必须可以安全地复制和分配给它们,而不会泄漏。所有Qt和C ++标准库类都不会在这种使用下编译,或者会正常运行。如果您使用的是裸露的指针,那么您已经将自己开枪了,所以至少要使用适当的QSharedPointer。
在编辑之前,您没有说出对象是什么。
如果您将原始指针存储在列表中,那么这样做肯定会泄漏内存clear()。A 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
Run Code Online (Sandbox Code Playgroud)
这将泄漏内存,并且几乎不需要编写这样的代码:
QList<QString*> stringList3;
stringList3 << new QString("Foo") << new QString("Bar") << new QString("Baz");
stringList3.clear();
Run Code Online (Sandbox Code Playgroud)
还要注意QList,以及所有不错的C ++容器类型都是RAII。这意味着他们将在销毁时释放其使用的资源。这意味着clear()除非您确实希望清除列表,否则您无需在列表上调用a 。此代码不会泄漏资源。main()列表的析构函数将在返回之前被调用,并且列表的析构函数将破坏所有字符串,并且它们都将正确释放分配的堆内存。
int main() {
QList<QString> stringList1;
stringList1 << "Foo" << "Bar" << "Baz";
return 0;
}
Run Code Online (Sandbox Code Playgroud)