Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Why QNetworkReply run-time crash on deleteLater() ?
QtWS25 Last Chance

Why QNetworkReply run-time crash on deleteLater() ?

Scheduled Pinned Locked Moved Solved General and Desktop
qnetworkreplycrashdeletelaterqtnetwork
10 Posts 3 Posters 4.0k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • I Offline
    I Offline
    IMAN4K
    wrote on 24 Aug 2018, 07:55 last edited by
    #1

    Hi everyone.
    Please look at this piece of code for QNetworkReply slot:

    void MyClass::someSlot(QNetworkReply* reply) {
    		if (reply->error()) {
    			log(QString("{%1(%2)} network error(%3)").arg(__FILE__).arg(__LINE__).arg(reply->errorString()));
    			emit netError(reply->error(), reply->errorString());
    			return;
    		}
    
    		const auto map = QJsonDocument::fromJson(reply->readAll()).object().toVariantMap();
    		if (!map.find(QStringLiteral("success")).value().toBool()) {
    			const auto msg = map.find(QStringLiteral("message")).value().toString();
    			log(QString("{%1(%2)} API error(%3)").arg(__FILE__).arg(__LINE__).arg(msg));
    			emit apiError(map.find(QStringLiteral("errorCode")).value().toInt(), msg);
    			return;
    		}
    
    		const auto token = map.find(QStringLiteral("registration_token")).value().toString();
    		const auto inviteURL = map.find(QStringLiteral("complete_invite_url")).value().toUrl();
    		const auto pollingURL = map.find(QStringLiteral("polling_url")).value().toUrl();
    		const auto timeOut = map.find(QStringLiteral("token_duration")).value().toInt();
    		QString printerID;
    
    		const auto items = QUrlQuery(pollingURL).queryItems();
    		for (const auto id : items) {
    			if (id.first == QStringLiteral("printerid"))
    				printerID = id.second;
    		}
    		log(QString("anonymous registration successed (printerid:%1)").arg(printerID));
    		emit registered(token, printerID, inviteURL, pollingURL, QTime(0, 0, 0).addSecs(timeOut));
    
    		reply->deleteLater();
    	}
    

    Why i'm getting crash on reply->deleteLater(); ?

    Doc clearly says about QNetworkAccessManager::finished(QNetworkReply *reply):

    Note: Do not delete the reply object in the slot connected to this signal. Use deleteLater().

    R 1 Reply Last reply 24 Aug 2018, 07:59
    0
    • I IMAN4K
      24 Aug 2018, 07:55

      Hi everyone.
      Please look at this piece of code for QNetworkReply slot:

      void MyClass::someSlot(QNetworkReply* reply) {
      		if (reply->error()) {
      			log(QString("{%1(%2)} network error(%3)").arg(__FILE__).arg(__LINE__).arg(reply->errorString()));
      			emit netError(reply->error(), reply->errorString());
      			return;
      		}
      
      		const auto map = QJsonDocument::fromJson(reply->readAll()).object().toVariantMap();
      		if (!map.find(QStringLiteral("success")).value().toBool()) {
      			const auto msg = map.find(QStringLiteral("message")).value().toString();
      			log(QString("{%1(%2)} API error(%3)").arg(__FILE__).arg(__LINE__).arg(msg));
      			emit apiError(map.find(QStringLiteral("errorCode")).value().toInt(), msg);
      			return;
      		}
      
      		const auto token = map.find(QStringLiteral("registration_token")).value().toString();
      		const auto inviteURL = map.find(QStringLiteral("complete_invite_url")).value().toUrl();
      		const auto pollingURL = map.find(QStringLiteral("polling_url")).value().toUrl();
      		const auto timeOut = map.find(QStringLiteral("token_duration")).value().toInt();
      		QString printerID;
      
      		const auto items = QUrlQuery(pollingURL).queryItems();
      		for (const auto id : items) {
      			if (id.first == QStringLiteral("printerid"))
      				printerID = id.second;
      		}
      		log(QString("anonymous registration successed (printerid:%1)").arg(printerID));
      		emit registered(token, printerID, inviteURL, pollingURL, QTime(0, 0, 0).addSecs(timeOut));
      
      		reply->deleteLater();
      	}
      

      Why i'm getting crash on reply->deleteLater(); ?

      Doc clearly says about QNetworkAccessManager::finished(QNetworkReply *reply):

      Note: Do not delete the reply object in the slot connected to this signal. Use deleteLater().

      R Offline
      R Offline
      raven-worx
      Moderators
      wrote on 24 Aug 2018, 07:59 last edited by
      #2

      @IMAN4K
      maybe because the reply is already deleted somewhere else?

      btw. you have 2 return statements in your slot implementation which do not delete the reply object.

      --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
      If you have a question please use the forum so others can benefit from the solution in the future

      I 1 Reply Last reply 24 Aug 2018, 08:05
      3
      • R raven-worx
        24 Aug 2018, 07:59

        @IMAN4K
        maybe because the reply is already deleted somewhere else?

        btw. you have 2 return statements in your slot implementation which do not delete the reply object.

        I Offline
        I Offline
        IMAN4K
        wrote on 24 Aug 2018, 08:05 last edited by IMAN4K
        #3

        @raven-worx
        Hi.
        deleted where ? i didn't deleted in my code
        If it was suppose to be deleted somewhere else or QNetworkAccessManager takes the ownership, so why should we use deleteLater ?

        Yes, should take care of that two returns.

        R 1 Reply Last reply 24 Aug 2018, 08:10
        0
        • I IMAN4K
          24 Aug 2018, 08:05

          @raven-worx
          Hi.
          deleted where ? i didn't deleted in my code
          If it was suppose to be deleted somewhere else or QNetworkAccessManager takes the ownership, so why should we use deleteLater ?

          Yes, should take care of that two returns.

          R Offline
          R Offline
          raven-worx
          Moderators
          wrote on 24 Aug 2018, 08:10 last edited by raven-worx
          #4

          @IMAN4K said in Why QNetworkReply run-time crash on deleteLater() ?:

          deleted where ? i didn't deleted in my code

          ok, then lets start over again.
          What exactly makes you sure that deleteLater() causes the crash?
          Can you post a callstack at the time of the crash?

          --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
          If you have a question please use the forum so others can benefit from the solution in the future

          I 1 Reply Last reply 24 Aug 2018, 08:24
          0
          • R raven-worx
            24 Aug 2018, 08:10

            @IMAN4K said in Why QNetworkReply run-time crash on deleteLater() ?:

            deleted where ? i didn't deleted in my code

            ok, then lets start over again.
            What exactly makes you sure that deleteLater() causes the crash?
            Can you post a callstack at the time of the crash?

            I Offline
            I Offline
            IMAN4K
            wrote on 24 Aug 2018, 08:24 last edited by IMAN4K
            #5

            @raven-worx
            Simple, if i remove reply->deleteLater() there's no crash!
            someSlot is a lambda in initRegister function in my source code:

            enter image description here

            J R 2 Replies Last reply 24 Aug 2018, 08:35
            0
            • I IMAN4K
              24 Aug 2018, 08:24

              @raven-worx
              Simple, if i remove reply->deleteLater() there's no crash!
              someSlot is a lambda in initRegister function in my source code:

              enter image description here

              J Offline
              J Offline
              J.Hilk
              Moderators
              wrote on 24 Aug 2018, 08:35 last edited by
              #6

              @IMAN4K said in Why QNetworkReply run-time crash on deleteLater() ?:

              someSlot is a lambda in initRegister function in my source code:

              we're getting closer,

              can you show us the whole code secetion/function, where the lambda is defined? You're most likely accessing the reply pointer there, somewhere, outside the lambda scope.


              Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


              Q: What's that?
              A: It's blue light.
              Q: What does it do?
              A: It turns blue.

              1 Reply Last reply
              1
              • I Offline
                I Offline
                IMAN4K
                wrote on 24 Aug 2018, 08:56 last edited by
                #7

                Here's the interesting part:
                api.h:

                	class HTTPWorker : public QObject {
                		Q_OBJECT
                
                	public:
                		HTTPWorker(QThread*, const QUrl&, const QUrlQuery&);
                		~HTTPWorker();
                
                		private Q_SLOTS:
                		void post();
                
                	private:
                		QNetworkAccessManager manager;
                		QUrlQuery params;
                		QUrl url;
                
                	Q_SIGNALS:
                		void finished(QNetworkReply*);
                	};
                
                	class GCPConnector : public QObject {
                		Q_OBJECT
                
                	public:
                		GCPConnector(QObject* parent = nullptr);
                
                		/*
                			returns capabilities and specifications for
                			a printer(required in anonymous registeration)
                		*/
                		static QByteArray printerCapabilites(const QPrinter&);
                
                		public Q_SLOTS:
                		/* first time anonymous registration for connector-based Printers */
                		void initRegister(const QPrinter& = QPrinter());
                
                		/* complete printer registration & get authorization code */
                		void getAuthorizationCode(const QUrl& polling_url, const QString& client_id);
                
                		/* get access & refresh tokens as last step */
                		void getTokens(const QString& client_id, const QString& secret, const QString& authorization_code);
                
                	signals:
                		void netError(NetworkError error_code, QString error_str);
                		void apiError(int code, QString detail);
                		void registered(QString token, QString printer_id, QUrl invite_url, QUrl polling_url, QTime time_out /* token life time */);
                		void authorized(QString authorization_code, QString user_email, QUrl confirm_url);
                
                	protected:
                		void post(const QUrl&, const QUrlQuery&, std::function<void(QNetworkReply*)> /* slot */);
                
                	private:
                		struct APIData {
                			QString access_token;
                			QString refresh_token;
                		} _data;
                	};
                

                api.cpp

                #include "api.h"
                
                namespace GCPAPI {
                
                	HTTPWorker::HTTPWorker(QThread* thread, const QUrl& _url, const QUrlQuery& _params) :url{ _url }, params{ _params } {
                		moveToThread(thread);
                		manager.moveToThread(thread);
                
                		QObject::connect(thread, &QThread::started, this, &HTTPWorker::post);
                		QObject::connect(this, &HTTPWorker::finished, thread, &QThread::quit);
                		QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
                		QObject::connect(thread, &QThread::finished, this, &HTTPWorker::deleteLater);
                	}
                
                	HTTPWorker::~HTTPWorker() {
                
                	}
                
                	void HTTPWorker::post() {
                		QNetworkRequest req(url);
                		req.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/x-www-form-urlencoded"));
                		const auto data = params.isEmpty() ? url.toEncoded() : params.toString(QUrl::FullyEncoded).toUtf8();
                		manager.post(req, data);
                		QObject::connect(&manager, &QNetworkAccessManager::finished, this, &HTTPWorker::finished);
                	}
                
                
                	GCPConnector::GCPConnector(QObject* parent) :QObject(parent) {
                		
                	}
                
                	void GCPConnector::post(const QUrl& url, const QUrlQuery& params, std::function<void(QNetworkReply*)> slot) {
                		QThread* local = new QThread;
                		HTTPWorker* worker = new HTTPWorker(local, url, params);
                		QObject::connect(worker, &HTTPWorker::finished, this, slot);
                		local->start();
                	}
                
                	QByteArray GCPConnector::printerCapabilites(const QPrinter& printer) {
                		QPrinterInfo info(printer);
                		QJsonDocument doc;
                		QJsonObject mainObj, printerObj;
                		mainObj.insert(QStringLiteral("version"), QStringLiteral("1.0"));
                
                		/* collate */
                		{
                			QJsonObject obj;
                			obj.insert(QStringLiteral("default"), printer.collateCopies());
                			printerObj.insert(QStringLiteral("collate"), obj);
                		}
                
                		/* content type */
                		{
                			QJsonObject obj;
                			QJsonArray array;
                			obj.insert(QStringLiteral("content_type"), QStringLiteral("application/pdf"));
                			array << obj;
                			printerObj.insert(QStringLiteral("supported_content_type"), array);
                		}
                
                		/* duplex mode */
                		{
                			QJsonObject obj;
                			QJsonArray array;
                			QJsonArray optionArray;
                			const auto dmode = printer.duplex();
                			QJsonObject obj1;
                			obj1.insert(QStringLiteral("type"), QStringLiteral("NO_DUPLEX"));
                			obj1.insert(QStringLiteral("is_default"), dmode == QPrinter::DuplexNone);
                			QJsonObject obj2;
                			obj2.insert(QStringLiteral("type"), QStringLiteral("LONG_EDGE"));
                			obj2.insert(QStringLiteral("is_default"), dmode == QPrinter::DuplexLongSide);
                			QJsonObject obj3;
                			obj3.insert(QStringLiteral("type"), QStringLiteral("SHORT_EDGE"));
                			obj3.insert(QStringLiteral("is_default"), dmode == QPrinter::DuplexShortSide);
                			optionArray << obj1 << obj2 << obj3;
                			obj.insert(QStringLiteral("option"), optionArray);
                
                			printerObj.insert(QStringLiteral("duplex"), obj);
                		}
                		
                		/* dpi */
                		{
                			QJsonArray array;
                			QJsonObject optionObj;
                			optionObj.insert(QStringLiteral("horizontal_dpi"), printer.physicalDpiX());
                			optionObj.insert(QStringLiteral("vendor_id"), QString::number(printer.physicalDpiX()) + QStringLiteral("dpi"));
                			optionObj.insert(QStringLiteral("vertical_dpi"), printer.physicalDpiY());
                			optionObj.insert(QStringLiteral("custom_display_name"), QString::number(printer.physicalDpiY()) + QStringLiteral("dpi"));
                			optionObj.insert(QStringLiteral("is_default"), true);
                			array << optionObj;
                			QJsonObject obj;
                			obj.insert(QStringLiteral("option"), array);
                			printerObj.insert(QStringLiteral("dpi"), obj);
                		}
                
                		/* color */
                		{
                			QJsonObject obj, obj1, obj2;
                			QJsonArray optionArray;
                			obj1.insert(QStringLiteral("type"), QStringLiteral("STANDARD_MONOCHROME"));
                			obj1.insert(QStringLiteral("is_default"), printer.colorMode() == QPrinter::GrayScale);
                			obj2.insert(QStringLiteral("type"), QStringLiteral("STANDARD_COLOR"));
                			obj2.insert(QStringLiteral("is_default"), printer.colorMode() == QPrinter::Color);
                			optionArray << obj1 << obj2;
                			obj.insert(QStringLiteral("option"), optionArray);
                			printerObj.insert(QStringLiteral("color"), obj);
                		}
                		
                		/* vendor capabilities */
                		{
                			QJsonArray vendorArray;
                			/* Page Orientation */
                			QJsonObject poObj;
                			poObj.insert(QStringLiteral("id"), QStringLiteral("PageOrientation"));
                			poObj.insert(QStringLiteral("display_name"), QStringLiteral("PageOrientation"));
                			poObj.insert(QStringLiteral("type"), QStringLiteral("SELECT"));
                			poObj.insert(QStringLiteral("display_name"), QStringLiteral("PageOrientation"));
                			QJsonArray tArray1;
                			QJsonObject tObj1;
                			{
                				QJsonObject obj1;
                				obj1.insert(QStringLiteral("display_name"), QStringLiteral("Portrait"));
                				obj1.insert(QStringLiteral("is_default"), printer.orientation() == QPrinter::Portrait);
                				obj1.insert(QStringLiteral("value"), QStringLiteral("Portrait"));
                				QJsonObject obj2;
                				obj2.insert(QStringLiteral("display_name"), QStringLiteral("Landscape"));
                				obj2.insert(QStringLiteral("is_default"), printer.orientation() == QPrinter::Landscape);
                				obj2.insert(QStringLiteral("value"), QStringLiteral("Landscape"));
                				QJsonObject obj3;
                				obj3.insert(QStringLiteral("display_name"), QStringLiteral("RotatedLandscape"));
                				obj3.insert(QStringLiteral("is_default"), false);
                				obj3.insert(QStringLiteral("value"), QStringLiteral("RotatedLandscape"));
                				tArray1 << obj1 << obj2 << obj3;
                			}
                			tObj1.insert(QStringLiteral("option"), tArray1);
                			poObj.insert(QStringLiteral("select_cap"), tObj1);
                
                			/* Page Sizes */
                			QJsonObject psObj;
                			psObj.insert(QStringLiteral("id"), QStringLiteral("PageSize"));
                			psObj.insert(QStringLiteral("display_name"), QStringLiteral("PageSize"));
                			psObj.insert(QStringLiteral("type"), QStringLiteral("SELECT"));
                			psObj.insert(QStringLiteral("display_name"), QStringLiteral("PageSize"));
                			QJsonArray tArray2;
                			QJsonObject tObj2;
                
                			const auto psizes = info.supportedPageSizes();
                			for (const auto psize : psizes) {
                				QJsonObject t;
                				t.insert(QStringLiteral("display_name"), psize.key());
                				t.insert(QStringLiteral("value"), psize.name());
                				if (tArray2.isEmpty())
                					t.insert(QStringLiteral("is_default"), true);
                				tArray2 << t;
                			}
                			tObj2.insert(QStringLiteral("option"), tArray2);
                			psObj.insert(QStringLiteral("select_cap"), tObj2);
                			
                			vendorArray << poObj << psObj;
                			printerObj.insert(QStringLiteral("vendor_capability"), vendorArray);
                		}
                
                		mainObj.insert(QStringLiteral("printer"), printerObj);
                		doc.setObject(mainObj);
                
                		return doc.toJson(QJsonDocument::Compact);
                	}
                
                	void GCPConnector::initRegister(const QPrinter& printer) {
                		QUrl url(GCP_URL + GCP_REGISTER_PATH);
                		QUrlQuery params;
                		params.addQueryItem(QStringLiteral("name"), printer.printerName());
                		params.addQueryItem(QStringLiteral("proxy"), QUuid::createUuid().toString());
                		params.addQueryItem(QStringLiteral("capabilities"), printerCapabilites(printer));
                		params.addQueryItem(QStringLiteral("use_cdd"), QStringLiteral("true"));
                		log(QString("registering printer (%1) as anonymous to GCP...").arg(printer.printerName()));
                
                		post(url, params, [this] (QNetworkReply* reply) {
                			if (reply->error() != NetworkError::NoError) {
                				log(QString("{%1(%2)} network error(%3)").arg(__FILE__).arg(__LINE__).arg(reply->errorString()));
                				emit netError(reply->error(), reply->errorString());
                				return;
                			}
                
                			const auto map = QJsonDocument::fromJson(reply->readAll()).object().toVariantMap();
                			if (!map.find(QStringLiteral("success")).value().toBool()) {
                				const auto msg = map.find(QStringLiteral("message")).value().toString();
                				log(QString("{%1(%2)} API error(%3)").arg(__FILE__).arg(__LINE__).arg(msg));
                				emit apiError(map.find(QStringLiteral("errorCode")).value().toInt(), msg);
                				return;
                			}
                
                			const auto token = map.find(QStringLiteral("registration_token")).value().toString();
                			const auto inviteURL = map.find(QStringLiteral("complete_invite_url")).value().toUrl();
                			const auto pollingURL = map.find(QStringLiteral("polling_url")).value().toUrl();
                			const auto timeOut = map.find(QStringLiteral("token_duration")).value().toInt();
                			QString printerID;
                
                			const auto items = QUrlQuery(pollingURL).queryItems();
                			for (const auto id : items) {
                				if (id.first == QStringLiteral("printerid"))
                					printerID = id.second;
                			}
                			log(QString("anonymous registration successed (printerid:%1)").arg(printerID));
                			emit registered(token, printerID, inviteURL, pollingURL, QTime(0, 0, 0).addSecs(timeOut));
                		});
                	}
                
                	void GCPConnector::getAuthorizationCode(const QUrl& _url, const QString& client_id) {
                		QUrl url;
                		url.setUrl(_url.toString() + client_id);
                		log("getting API authorization code...");
                
                		post(url, QUrlQuery(), [this](QNetworkReply* reply) {
                			if (reply->error()) {
                				log(QString("{%1(%2)} network error(%3)").arg(__FILE__).arg(__LINE__).arg(reply->errorString()));
                				emit netError(reply->error(), reply->errorString());
                				return;
                			}
                
                			const auto map = QJsonDocument::fromJson(reply->readAll()).object().toVariantMap();
                			if (!map.find(QStringLiteral("success")).value().toBool()) {
                				const auto msg = map.find(QStringLiteral("message")).value().toString();
                				log(QString("{%1(%2)} API error(%3)").arg(__FILE__).arg(__LINE__).arg(msg));
                				emit apiError(0, msg);
                				return;
                			}
                			
                			const auto auth_code = map.find(QStringLiteral("authorization_code")).value().toString();
                			const auto jabberID = map.find(QStringLiteral("xmpp_jid")).value().toString();
                			const auto confirmURL = map.find(QStringLiteral("confirmation_page_url")).value().toUrl();
                			const auto email = map.find(QStringLiteral("user_email")).value().toString();
                			log(QString("printer has successfully registered for %1").arg(email));
                			store(QStringLiteral("xmpp_jid"), jabberID);
                			emit authorized(auth_code, email, confirmURL);
                		});
                	}
                
                	void GCPConnector::getTokens(const QString& client_id, const QString& secret, const QString& authorization_code) {
                		QUrl url(QStringLiteral("https://accounts.google.com/o/oauth2/token"));
                		QUrlQuery params;
                		params.addQueryItem(QStringLiteral("client_id"), client_id);
                		params.addQueryItem(QStringLiteral("redirect_uri"), QStringLiteral("oob"));
                		params.addQueryItem(QStringLiteral("client_secret"), secret);
                		params.addQueryItem(QStringLiteral("grant_type"), QStringLiteral("authorization_code"));
                		params.addQueryItem(QStringLiteral("code"), authorization_code);
                		log("getting API access tokens...");
                
                		post(url, params, [this](QNetworkReply* reply) {
                			if (reply->error()) {
                				const auto err_str = reply->errorString();
                				log(QString("{%1(%2)} network error(%3)").arg(__FILE__).arg(__LINE__).arg(err_str));
                				emit netError(reply->error(), err_str);
                				return;
                			}
                
                			const auto map = QJsonDocument::fromJson(reply->readAll()).object().toVariantMap();
                			const auto rtoken = map.find(QStringLiteral("refresh_token")).value().toString();
                			const auto atoken = map.find(QStringLiteral("access_token")).value().toString();
                			const auto expire_time = map.find(QStringLiteral("expires_in")).value().toInt();
                			log("printer registration process done! tokens received...");
                			store(QStringLiteral("refresh_token"), rtoken);
                			QTimer::singleShot((expire_time - 60) * 1000, this, SLOT(onTokenExpire()));
                			_data.access_token = atoken;
                			_data.refresh_token = rtoken;
                		});
                	}
                
                	void GCPConnector::onTokenExpire() {
                
                	}
                
                	void GCPConnector::apiCall() {
                		QUrlQuery params;
                		params.addQueryItem(QStringLiteral("access_token"), _data.access_token);
                	}
                
                } // namespace GCPAPI
                

                don't know what part i'm missing!

                1 Reply Last reply
                0
                • I IMAN4K
                  24 Aug 2018, 08:24

                  @raven-worx
                  Simple, if i remove reply->deleteLater() there's no crash!
                  someSlot is a lambda in initRegister function in my source code:

                  enter image description here

                  R Offline
                  R Offline
                  raven-worx
                  Moderators
                  wrote on 24 Aug 2018, 11:56 last edited by
                  #8

                  @IMAN4K said in Why QNetworkReply run-time crash on deleteLater() ?:

                  someSlot is a lambda in initRegister function in my source code:

                  well that makes big difference and doesn't actually relate to the code you've posted.

                  The problem is:
                  QObject::connect(worker, &HTTPWorker::finished, this, slot)

                  The signal-slot connection remains "active" as long as worker and this is still alive.
                  So any previous lambda method is still called when the finished is triggered again as long as this is true. So a reply object from a previous call might be deleted, but is still executed.
                  You need to disconnect the signal-slot connection when all the work has been done or at least make sure.

                  Some possible solutions:

                  void GCPConnector::post(const QUrl& url, const QUrlQuery& params, std::function<void(QNetworkReply*)> slot) {
                                   ...
                  		QObject::connect(worker, &HTTPWorker::finished, reply, slot);  // bind to reply somehow
                                  ...
                  	}
                  
                  void GCPConnector::post(const QUrl& url, const QUrlQuery& params, std::function<void(QNetworkReply*)> slot) {
                  		QThread* local = new QThread;
                  		HTTPWorker* worker = new HTTPWorker(local, url, params);
                  		QObject::connect(worker, &HTTPWorker::finished, worker , slot); // bind to worker, and ensure it is deleted when it has finished work, etc.
                  		local->start();
                  	}
                  

                  --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
                  If you have a question please use the forum so others can benefit from the solution in the future

                  I 1 Reply Last reply 25 Aug 2018, 12:59
                  4
                  • R raven-worx
                    24 Aug 2018, 11:56

                    @IMAN4K said in Why QNetworkReply run-time crash on deleteLater() ?:

                    someSlot is a lambda in initRegister function in my source code:

                    well that makes big difference and doesn't actually relate to the code you've posted.

                    The problem is:
                    QObject::connect(worker, &HTTPWorker::finished, this, slot)

                    The signal-slot connection remains "active" as long as worker and this is still alive.
                    So any previous lambda method is still called when the finished is triggered again as long as this is true. So a reply object from a previous call might be deleted, but is still executed.
                    You need to disconnect the signal-slot connection when all the work has been done or at least make sure.

                    Some possible solutions:

                    void GCPConnector::post(const QUrl& url, const QUrlQuery& params, std::function<void(QNetworkReply*)> slot) {
                                     ...
                    		QObject::connect(worker, &HTTPWorker::finished, reply, slot);  // bind to reply somehow
                                    ...
                    	}
                    
                    void GCPConnector::post(const QUrl& url, const QUrlQuery& params, std::function<void(QNetworkReply*)> slot) {
                    		QThread* local = new QThread;
                    		HTTPWorker* worker = new HTTPWorker(local, url, params);
                    		QObject::connect(worker, &HTTPWorker::finished, worker , slot); // bind to worker, and ensure it is deleted when it has finished work, etc.
                    		local->start();
                    	}
                    
                    I Offline
                    I Offline
                    IMAN4K
                    wrote on 25 Aug 2018, 12:59 last edited by
                    #9

                    @raven-worx

                    So any previous lambda method is still called when the finished is triggered again as long as this is true

                    Sorry for late reply.
                    I'm not sure but think this is not true because Although connection is alive until sender & receiver is alive BUT after thread destruction, sender OR the worker get deleted too! and there is no sender to trigger signal (am i right ?)
                    QObject::connect(thread, &QThread::finished, this, &HTTPWorker::deleteLater);

                    1 Reply Last reply
                    0
                    • I Offline
                      I Offline
                      IMAN4K
                      wrote on 25 Aug 2018, 14:41 last edited by IMAN4K
                      #10

                      At long last! i decided to simply process reply in worker thread(Thanks @raven-worx ):

                              using Header = QMap<QString, QString>;
                      
                      	class HttpWorker : public QObject {
                      		Q_OBJECT
                      
                      	public:
                      		struct HttpData {
                      			bool hasError = false;
                      			NetworkError error = NetworkError::NoError;
                      			QString errorString;
                      			QByteArray data;
                      		};
                      		HttpWorker(QThread*, const QUrl&, const QUrlQuery&);
                      		~HttpWorker();
                      
                      		void addHeaders(const Header&);
                      
                      		enum Method {
                      			Post, Get
                      		};
                      		void setMethod(Method m) {
                      			http_method = m;
                      		}
                      		Method method() const {
                      			return http_method;
                      		}
                      
                      		private Q_SLOTS:
                      		void sendRequest();
                      
                      	private:
                      		QNetworkAccessManager manager;
                      		Header headers;
                      		QUrlQuery params;
                      		QUrl url;
                      		Method http_method = Post;
                      
                      	private:
                      		void check(QNetworkReply*);
                      		void appendHeaders(QNetworkRequest*);
                      
                      	Q_SIGNALS:
                      		void finished(HttpData);
                      	};
                      
                      	HttpWorker::HttpWorker(QThread* thread, const QUrl& _url, const QUrlQuery& _params) :url{ _url }, params{ _params } {
                      		qRegisterMetaType<HttpData>("HttpData");
                      		moveToThread(thread);
                      		manager.moveToThread(thread);
                      
                      		QObject::connect(thread, &QThread::started, this, &HttpWorker::sendRequest);
                      		QObject::connect(this, &HttpWorker::finished, thread, &QThread::quit);
                      		QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
                      		QObject::connect(thread, &QThread::finished, this, &HttpWorker::deleteLater);
                      		QObject::connect(&manager, &QNetworkAccessManager::finished, this, &HttpWorker::check);
                      	}
                      
                      	HttpWorker::~HttpWorker() {
                      
                      	}
                      
                      	void HttpWorker::addHeaders(const Header& _headers) {
                      		headers = std::move(_headers);
                      	}
                      
                      	void HttpWorker::appendHeaders(QNetworkRequest* req) {
                      		if (!req)
                      			return;
                      
                      		QMapIterator<QString, QString> iterator(headers);
                      		while (iterator.hasNext()) {
                      			iterator.next();
                      			req->setRawHeader(QByteArray::fromStdString(iterator.key().toStdString()), QByteArray::fromStdString(iterator.value().toStdString()));
                      		}
                      	}
                      
                      	void HttpWorker::sendRequest() {
                      		const auto content_h = QStringLiteral("application/x-www-form-urlencoded");
                      		if (method() == Post) {
                      			QNetworkRequest req(url);
                      			req.setHeader(QNetworkRequest::ContentTypeHeader, content_h);
                      			if (!headers.isEmpty())
                      				appendHeaders(&req);
                      			const auto data = params.isEmpty() ? url.toEncoded() : params.toString(QUrl::FullyEncoded).toUtf8();
                      			manager.post(req, data);
                      		} else {
                      			url.setQuery(params);
                      			QNetworkRequest req(url);
                      			req.setHeader(QNetworkRequest::ContentTypeHeader, content_h);
                      			manager.get(req);
                      		}
                      	}
                      
                      	void HttpWorker::check(QNetworkReply* reply) {
                      		HttpData data;
                      		if (reply->error()) {
                      			data.hasError = true;
                      			data.error = reply->error();
                      			data.errorString = reply->errorString();
                      		} else {
                      			data.data = std::move(reply->readAll());
                      		}
                      		emit finished(std::move(data));
                      
                      		reply->deleteLater();
                      	}
                      
                      1 Reply Last reply
                      0

                      2/10

                      24 Aug 2018, 07:59

                      topic:navigator.unread, 8
                      • Login

                      • Login or register to search.
                      2 out of 10
                      • First post
                        2/10
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved