0

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

'delete'行を称賛すると、どの方法でもアプリを正常に実行できますが、メモリがリークします。

何が得られますか?valgrindは、デストラクタが機能するための何らかの遅延をもたらしますか?どうすればこれを解決できますか?

4

4 に答える 4

4

ハイドの答えは正しいです。ただし、特定のハッシュをクリアする最も簡単な方法は次のとおりです。

#include <QtAlgorithms>

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

ハッシュテーブルのキーがポインタ(例)の場合、上記の手法は機能しないことに注意してくださいQHash<QString*, QVariant>

于 2012-11-05T16:59:06.453 に答える
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は通常値として保持するのに適しています。

于 2012-11-05T15:37:45.143 に答える
1

ドキュメントには明示的に記載されていませんが、繰り返し処理しているコンテナを変更していることが問題です。

toのコードforeachここにあります。

コードを見ると、コードとコードは基本的に次のように記述した場合と同じように機能します。

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

ただし、メンバー関数が既存のイテレータ(および)takeの無効化をトリガーする可能性があるため、イテレータがぶら下がり、未定義の動作が発生する可能性があります。itend

考えられる解決策:*反復中に反復するコンテナーを変更しないでください*次の反復が始まる前に有効であることを確認し、 -iteratoritを格納しないでください(この解決策ではの使用が禁止されています)endforeach

于 2012-11-05T15:28:54.343 に答える
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);
于 2012-11-05T15:32:05.923 に答える