首页 > 解决方案 > QT 网络崩溃

问题描述

我在访问网络请求的回复对象时收到 SIGSEGV。如果我这样做,它工作正常:

QNetworkAccessManager manager;

/**
 * Main entry point.
 */
int main(int argc, char *argv[])
{
    Configuration configuration;
    QApplication a(argc, argv);

    MainWindow w;
    w.show();

    QNetworkRequest * req = new QNetworkRequest(QUrl("http://localhost:5000/status/health"));
    QNetworkReply * reply = manager.get(*req);

    QObject::connect(reply, &QNetworkReply::finished, [&]{
        QByteArray read = reply->readAll();
        std::string readStr = read.toStdString();
        std::cout << "Got reply: " << readStr << endl;

        reply->close();
        reply->deleteLater();
    });
    return a.exec();
}

但这确实是一个 SIGSEGV:

QNetworkAccessManager manager;

void doRequest() {
    QNetworkRequest * req = new QNetworkRequest(QUrl("http://localhost:5000/status/health"));
    QNetworkReply * reply = manager.get(*req);

    QObject::connect(reply, &QNetworkReply::finished, [&]{
        QByteArray read = reply->readAll();
        std::string readStr = read.toStdString();
        std::cout << "Got reply: " << readStr << endl;

        reply->close();
        reply->deleteLater();
    });
}


/**
 * Main entry point.
 */
int main(int argc, char *argv[])
{
    Configuration configuration;
    QApplication a(argc, argv);

    MainWindow w;
    w.show();

    doRequest();

    return a.exec();
}

所以有些东西超出了范围。我不知道是什么。所以我这样做了:

static QNetworkReply * reply;

void doRequest() {
    QNetworkRequest req(QUrl("http://localhost:5000/status/health"));
    reply = manager.get(req);

    QObject::connect(reply, &QNetworkReply::finished, [&]{
        QByteArray read = reply->readAll();
        std::string readStr = read.toStdString();
        std::cout << "Got reply: " << readStr << endl;

        reply->close();
        reply->deleteLater();
    });
}

这不是 SIGSEGV。我不知道为什么不。

我对 lambdas 如何与 [&] 一起工作真的很愚蠢吗?或者 QNetworkReply 对象到底是什么?这真的是一个智能指针吗?因为它超出了范围,所以它被销毁了?

有没有人有指向从我的 GUI 中调用网络功能的正确方法的指针?我正在做这一切是为了让它在单击按钮时起作用。也许我需要自己保留回复对象并在那个 lambda 中忘记它们。我不知道。我找到的示例都是独立的,就像我的原始代码一样。

标签: c++qt

解决方案


lambda 中的 [&] 符号非常危险。特别是在异步环境中。

所以我要告诉你为什么:

QNetworkReply * reply = manager.get(*req);

QObject::connect(reply, &QNetworkReply::finished, [&]{
    QByteArray read = reply->readAll();
    std::string readStr = read.toStdString();
    std::cout << "Got reply: " << readStr << endl;

    reply->close();
    reply->deleteLater();
});

您正在通过引用捕获回复指针。在作用域的末尾,回复指针被销毁,并且您有一个对垃圾的引用。

解决方案是按值捕获回复指针:

QNetworkReply * reply = manager.get(*req);

QObject::connect(reply, &QNetworkReply::finished, [reply]{
    QByteArray read = reply->readAll(); // Works well, it's a fresh copy of the pointer
    std::string readStr = read.toStdString();
    std::cout << "Got reply: " << readStr << endl;

    reply->close();
    reply->deleteLater();
});

推荐阅读