5

QtWebKit を使用したアプリケーションがあります。URL をロードし、レンダー ツリーにいくつかの統計をエクスポートします。コードのこのセクションは問題を引き起こしています:

...
if (mPage != 0) {
    disconnectSignals(mPage);
    delete mPage;
}
mPage = new Page(); //subclass of QWebPage
connectSignals(mPage);
QNetworkRequest req;
req.setUrl("http://...");
mPage->mainFrame()->load(req, QNetworkAccessManager::GetOperation);

上記のコードが最初に mPage=0 を実行すると、ページは正常に読み込まれ、他のすべては期待どおりに進みます。2 回目は、以前に作成されたページへのポインターであるため、切断されて削除されます。load() が制御をメイン イベント ループに戻した後、次のスタック トレースを含む SIGSEGV を取得します。

#0  0x00007ffff49a1e56 in QMetaObject::activate(QObject*, QMetaObject const*, int, void**)          () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtCore.so.4
#1  0x00007ffff6842972 in QWebFrame::loadFinished(bool) () from /home/ubuntu/3rdparty/qt-    4.8.1/lib/libQtWebKit.so.4
#2  0x00007ffff6881955 in ?? () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtWebKit.so.4
#3  0x00007ffff6bde3ab in ?? () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtWebKit.so.4
#4  0x00007ffff6c0ef14 in ?? () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtWebKit.so.4
#5  0x00007ffff6e0183b in ?? () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtWebKit.so.4
#6  0x00007ffff6e016e8 in ?? () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtWebKit.so.4
#7  0x00007ffff6e01755 in ?? () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtWebKit.so.4
#8  0x00007ffff6e0218c in ?? () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtWebKit.so.4
#9  0x00007ffff49a20c1 in QMetaObject::activate(QObject*, QMetaObject const*, int, void**) () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtCore.so.4
#10 0x00007ffff4d72b46 in ?? () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtNetwork.so.4
#11 0x00007ffff4de91c5 in ?? () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtNetwork.so.4
#12 0x00007ffff49a7286 in QObject::event(QEvent*) () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtCore.so.4
#13 0x00007ffff5243fa4 in QApplicationPrivate::notify_helper(QObject*, QEvent*) () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtGui.so.4
#14 0x00007ffff5248e23 in QApplication::notify(QObject*, QEvent*) () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtGui.so.4
#15 0x00007ffff498e21c in QCoreApplication::notifyInternal(QObject*, QEvent*) () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtCore.so.4
#16 0x00007ffff4991aba in QCoreApplicationPrivate::sendPostedEvents(QObject*, int,     QThreadData*) () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtCore.so.4
#17 0x00007ffff49bce53 in ?? () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtCore.so.4
#18 0x00007ffff235ba5d in g_main_context_dispatch () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#19 0x00007ffff235c258 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#20 0x00007ffff235c429 in g_main_context_iteration () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#21 0x00007ffff49bd27f in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtCore.so.4
#22 0x00007ffff52e78ae in ?? () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtGui.so.4
#23 0x00007ffff498d002 in QEventLoop::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtCore.so.4
#24 0x00007ffff498d257 in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () from /   home/ubuntu/3rdparty/qt-4.8.1/lib/libQtCore.so.4
#25 0x00007ffff4991db5 in QCoreApplication::exec() () from /home/ubuntu/3rdparty/qt-4.8.1/lib/libQtCore.so.4
#26 0x0000000000408ba0 in main (argc=3, argv=<optimized out>) at RenderTreeAnalyzer.cpp:474
4

2 に答える 2

5

イベント キューに配信されていないイベントが存在する可能性があるため、直接削除するのではなく、削除のスケジュールmPageを設定する必要があります。deleteLatermPage

制御がイベント ループに戻ると、Qt は削除されたオブジェクトにアクセスしようとするため、セグメンテーション違反が発生します。

newPage()ただし、コード例から、シグナルが必要な理由が完全にはわかりませんでした。

私の理解では、(seg-fault を回避するために) 十分なはずであり、ローカル/メンバー変数に新しい値 (つまり、 new へのポインター) をすぐmPage->deleteLater()に再割り当てできるはずです。mPagePage

oldPageをすぐに削除する必要がある場合は、イベント ループに戻る必要があるのは正しいことです。

イベント ループをトリガーし、削除要求を処理する機会がいくつかあります。

  1. キューに入れられたシグナル/スロット設定を使用する
  2. イベント キュー内のイベントを処理するために呼び出しQApplication::processEvents();た後に呼び出します。mPage->deleteLater()
  3. QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);すべての遅延削除のみを処理するために呼び出します。
  4. QCoreApplication::sendPostedEvents(mPage, QEvent::DeferredDelete);の遅延削除のみを処理するために呼び出しmPageます。

免責事項: 私はこれらの提案を明示的に試したことはありませんが (少なくとも最近覚えている限り)、最近 (もちろんドキュメントに加えて) 多くの Qt のイベント管理ソース コードをチェックしました。それらは機能します。

于 2012-06-15T14:59:06.163 に答える
3

問題はでしたdelete mPage;mPage->deleteLater(); emit getNext();代わりに使用する必要があります。deleteLater() は、次にプログラムがメイン イベント ループに戻ったときにオブジェクトを削除するようにスケジュールします。 emit getNext();でピックアップするスロットに接続されていmPage = new Page();ます。その接続タイプは Qt::QueuedConnection であるため、スロットを呼び出す前にイベント ループに屈します。正確な理由はわかりませんが、削除をスケジュールして、このようにイベント ループに戻り、古いシグナルを適切に閉じて新しいシグナルを設定する必要があります。

それで、これはうまくいきますが、誰かが何が起こっているのかをもっと詳しく教えてくれるなら、代わりにあなたのものを受け入れます. ありがとう。

于 2012-06-15T03:26:53.327 に答える