Simple http get test fails
-
I am writing a library that is based on HTTP communications. For the first step, I am trying to do nothing more than create an application that prints the response from an HTTP GET request. As you know, the QNetworkAccessManager::get method works by returning a QNetworkReply pointer, which generates signals to indicate important events, such as new incoming data, errors, and EOF. However, in my application, none of the signals appear to be generated. Moreover, the use of a packet capture utilty reveals that no packets are ever put on the wire in either direction. As I at wit's end, I am hopeful that someone can help me solve this issue.
nettest.hpp:
@#include <iostream>#include <QtCore>
#include <QtNetwork>class NetTest : public QObject {
public:
NetTest(QCoreApplication app, QObject parent = 0);
NetTest(QObject* parent = 0);public slots:
void run();private:
Q_OBJECTQCoreApplication *app;
QObject *parent;
};
@nettest.cpp
@#include <iostream>#include <QtCore>
#include <QtNetwork>#include "nettest.hpp"
NetTest::NetTest(QObject* parent) : QObject(parent) {
}
NetTest::NetTest(QCoreApplication app, QObject parent) : QObject(parent), app(app) {
}void NetTest::run() {
QNetworkAccessManager netman;
QUrl url("http://www.google.com/");
QNetworkRequest rqst(url);
QNetworkReply *rply = netman.get(rqst);QFile *out;
out = new QFile();
out->open(::stdout, QIODevice::WriteOnly);QMetaObject::Connection conn1, conn2, conn3;
conn1 = connect(rply, &QNetworkReply::readyRead, ={
out->write(rply->readAll());
out->flush();
});
conn2 = connect(rply, &QNetworkReply::finished, ={
out->close();
out->deleteLater();
rply->deleteLater();
disconnect(conn1);
disconnect(conn2);
disconnect(conn3);
app->quit();
});
conn3 = connect(rply, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error), [=](QNetworkReply::NetworkError code) {
out->write("Error: ");
out->write(rply->errorString().toUtf8());
out->write("\n");
out->flush();
out->close();
out->deleteLater();
rply->deleteLater();
disconnect(conn1);
disconnect(conn2);
disconnect(conn3);
app->quit();
});
}int main(int argc, char** argv) {
QCoreApplication app(argc, argv);
NetTest main(&app);
QMetaObject::invokeMethod(&main, "run", Qt::QueuedConnection);
return app.exec();
}
@nettest.pro
@TEMPLATE = app
CONFIG += debug
SOURCES += nettest.cpp
HEADERS += nettest.hpp
QT += network
QT -= gui
@ -
[quote author="brainchild" date="1367286126"]
@
void NetTest::run() {
QNetworkAccessManager netman;
@
[/quote]You made netman a local variable. It will be destroyed as soon as NetTest::run() returns. The connection will be lost as soon as netman is destroyed.To make your code work, make sure the QNetworkAccessManager doesn't get destroyed before the download finishes. You can create it on the heap (using new -- remember to invoke deleteLater() when you're done), or create it as a local variable in main() and then pass a pointer/reference into NetTest::run(). The 2nd method works because app.exec() doesn't return until qApp->quit() is invoked.
-
Thank you. This certainly solved the problem.
I guess I still don't understand C++ lambdas. I was under the impression that because of the = inside the [], the local variables in the named parent function are kept. For example, doing as you suggested, I put the deleteLater() call inside the error and finished lambdas. The pointer to the QNetworkAccessManager was entirely accessible. So why is the non-pointer version of the variable destroyed in my original version?
-
You're welcome :)
[=] doesn't capture all local variables from its calling function, only those that are used inside the body of the lambda (i.e. only the pointers "out" and "rply" are captured in your original code). Anyway, note that while you can capture a pointer to a QObject by value, you can't capture a QObject itself by value -- that requires the lambda to create a copy of the object, which is "disallowed":http://qt-project.org/doc/qt-5.0/qtcore/object.html#qt-objects-identity-vs-value .
But for discussion's sake, let's imagine you CAN capture an object allocated on the stack: Even though the lambda creates a copy for its own use, the original object will still be destroyed when the calling function returns.