Qt delete适用于Valgrind,但不能正常执行

时间:2012-11-05 15:20:14

标签: c++ qt valgrind delete-operator

我正在使用QtCreator和Valgrind检查Qt程序中的内存泄漏。我正在我的析构函数中删除QHash中的一些条目,如下所示:

QHash<QString, QVariant*> m_Hash;

/**
 * @brief
 * Destruct a Foo Class instance
 */
Foo ::~Foo ()
{

    // Do Cleanup here

    // Delete hash leftovers
    foreach( QString key, m_Hash.keys() )
    {

        qDebug() << "Deleting an entry..";

        // Delete the hash item
        delete m_Hash.take(key);

    }

}

如果我使用Valgrind调试此代码很好,并在调用析构函数时删除内容:

>> Deleting an entry.. 
>> Deleting an entry.. 

如果我在QtCreator中使用GDB启动,从QtCreator启动没有GDB,或者只是从命令行运行我的Qt应用程序,我会收到分段错误!

Signal name : 
SIGSEGV
Signal meaning : 
Segmentation fault

如果我推荐'删除'行,那么我可以使用任何方法运行我的应用程序,但我确实泄漏了内存。

是什么给出的? valgrind是否会引入某种延迟,使我的析构函数能够工作?我该如何解决这个问题?

4 个答案:

答案 0 :(得分:4)

海德的回答是正确的;但是,清除特定哈希的最简单方法如下:

#include <QtAlgorithms>

Foo::~Foo()
{
   qDeleteAll(m_Hash);
   m_Hash.clear();
}

请注意,如果哈希表的键是指针(例如QHash<QString*, QVariant>),则上述技术不起作用。

答案 1 :(得分:2)

您无法修改使用foreach迭代的容器。请改用迭代器。使用方法iterator QHash::erase ( iterator pos )更正代码:

 QMap<QString, QVariant* >::iterator it = m_Hash.begin();
 // auto it = m_Hash.begin(); // in C++11
 while (it != m_Hash.end()) {
     delete it.value();
     it = m_Hash.erase(it);
 }

此外,您存储QVariant指针而不是值的任何特定原因? QVariant通常适合保持值,因为您存储在QVariant中的大多数数据要么是隐式共享,要么是小的。

答案 2 :(得分:1)

documentation没有明确提及它,但是你正在改变你正在迭代的容器是一个问题。

foreach的代码是here

查看代码,它和你的代码基本上和你写的一样:

for (QHash::iterator it=m_Hash.begin(), end=m_Hash.end(); 
     it!=end;
     ++it)
{
    delete m_Hash.take(key);
}

但是,take成员函数可能会触发现有迭代器(itend)的失效,因此您的迭代器可能已经悬空,产生未定义的行为。

可能的解决方案: *在迭代时,不要修改通过迭代的容器 *确保it在下一次迭代开始之前有效,并且不存储end - 迭代器(此解决方案禁止使用foreach

答案 3 :(得分:0)

也许foreach关键字存在问题。尝试更换:

foreach( QString key, m_Hash.keys() )
{
    qDebug() << "Deleting an entry..";
    delete m_Hash.take(key);  // take changes the m_Hash object
}

使用:

for (QHash<QString, QVariant*>::iterator it =  m_Hash.begin();
                                         it != m_Hash.end(); ++it)
{
    qDebug() << "Deleting an entry..";
    delete it.value();      // we delete only what it.value() points to, but the 
                            // m_Hash object remains intact.
}
m_Hash.clear();

这样,当您遍历它时,哈希表保持不变。 foreach宏可能会扩展为一个构造,您可以“从脚下删除哈希表”。那就是宏可能会创建一个迭代器,它会变成无效或“悬空”作为调用的副作用

m_Hash.take(key);