5

QtSDK 4.7.3を使用しています

私は(void test())でこれをやっています:

mgr = new QNetworkAccessManager();
reply = mgr->get(QNetworkRequest(QUrl("http://developer.qt.nokia.com/fileNotExisting.txt")));

connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
    SLOT(onError(QNetworkReply::NetworkError)), Qt::ConnectionType::UniqueConnection);

そしてもちろんスロット onError が呼び出されます:

if (networkError == QNetworkReply::NetworkError::ContentNotFoundError)
{
// Messagebox starts an event loop which
// causes this slot to be called again
QMessageBox m;
m.exec();
}

onError スロットにメッセージボックス/イベントループがない場合、クラッシュは発生せず、すべてが機能します。しかし、そこにある場合、 m.exec() が呼び出されたときに onError スロットが再度呼び出されます。両方のメッセージ ボックスが閉じられ、関数 onError をそのままにしておくと、アプリケーションがクラッシュします。これが発生すると、アプリケーションはメモリの削除/解放を試みます。エラー「アクセス違反の読み取り場所」は役に立たず、コールスタックはQt dllの奥深くにあります。

私が確認し
たこと: 信号は 2 回接続されていません。
QApplication が exec 関数を呼び出す前後に test() を呼び出してみました。(重要ではない)。
HostNotFound のような別のエラーは、onError スロットを 2 回呼び出しません。
私のコードはすべてメインスレッドで実行されます。
一度だけ呼び出されるように onError スロットを切断しようとしましたが、それでもクラッシュします。
onError() のリクエストで abort を呼び出してみました。
同じ質問を Qt フォーラム ( post ) に投稿しました。

ここで何が起こっているのかを理解するのを手伝ってくれる人はいますか?

テストに使用するコードは次のとおりです。

#include "contentnotfound.h"
#include <QtGui/QApplication>
#include <QTimer>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

ContentNotFound cnf;

// false: start test after application's event loop have started
if (true) { cnf.test(); }
else { QTimer::singleShot(2000, &cnf, SLOT(test())); }

return a.exec();
}

contentnotfound.h

#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QMessageBox>

class ContentNotFound : public QObject
{
Q_OBJECT

public slots:
void test()
{
    mgr = new QNetworkAccessManager();
    reply = mgr->get(QNetworkRequest(QUrl("http://developer.qt.nokia.com/fileNotExisting.txt")));

    connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
        SLOT(onError(QNetworkReply::NetworkError)), Qt::ConnectionType::UniqueConnection);
}

private slots:
void onError(QNetworkReply::NetworkError networkError)
{
    //reply->disconnect(); // Disconnect all signals

    if (networkError == QNetworkReply::NetworkError::ContentNotFoundError)
    {
        // Messagebox starts an event loop which
        // causes this slot to be called again
        QMessageBox m;
        m.exec();
    }
}

private:
QNetworkAccessManager* mgr;
QNetworkReply* reply;

};
4

1 に答える 1

3

Qt < 4.8.0 にはバグがあります: https://bugreports.qt.io/browse/QTBUG-16333

キューに入れられた接続を変更すると、問題が解決します。

contentnotfound.h:

#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QMessageBox>

class ContentNotFound : public QObject
{
Q_OBJECT

public slots:
void test()
{
    qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
    mgr = new QNetworkAccessManager(this);
    reply = mgr->get(QNetworkRequest(QUrl("http://developer.qt.nokia.com/fileNotExisting.txt")));

    connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
        SLOT(onError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
}

private slots:
void onError(QNetworkReply::NetworkError networkError)
{
    //reply->disconnect(); // Disconnect all signals

    if (networkError == QNetworkReply::ContentNotFoundError)
    {
        // Messagebox starts an event loop which
        // causes this slot to be called again
        QMessageBox m;
        m.exec();
    }
}

private:
QNetworkAccessManager* mgr;
QNetworkReply* reply;

};
于 2011-10-04T20:21:34.040 に答える