QT Сетевые Сбои - PullRequest
       12

QT Сетевые Сбои

0 голосов
/ 22 мая 2019

Я получаю 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. И я понятия не имею, почему бы и нет.

Неужели я действительно глуп, что лямбды работают с [&]? Или это что-то волшебное в том, что такое объект QNetworkReply на самом деле ? Это действительно умный указатель, и поскольку он выпал из области видимости, он уничтожается?

У кого-нибудь есть указатель на правильный способ вызова сетевых функций из моего GUI? Я делаю все это, чтобы заставить это работать на нажатие кнопки. Может быть, мне нужно самому сохранить объекты ответа и забыть о них в этой лямбде. Я не знаю. Все примеры, которые я нашел, были автономными, как и мой оригинальный код.

1 Ответ

0 голосов
/ 22 мая 2019

Обозначение [&] в лямбдах действительно опасно. Особенно в асинхронной среде.

Итак, я покажу вам, почему:

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();
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...