QT的QNetworkAccessManager、QNetworkReply使用时应注意内存泄露问题。
原因在于他们收到的内容是个指针指向的内存,需要我们手动 deleteLater()。
一、下面是测试代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QtDebug>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
QString path="http://192.168.2.170:8091/simpletest01/API/cTest";
QNetworkAccessManager m_pManager1;
QNetworkRequest request1;
QNetworkReply *reply1=nullptr;
QNetworkAccessManager m_pManager2;
QNetworkRequest request2;
QNetworkReply *reply2=nullptr;
QNetworkAccessManager m_pManager3;
QNetworkRequest request3;
QNetworkReply *reply3=nullptr;
public slots:
void replyfinished(); //对应 QNetworkReply 的 finish信号
void m_pManagerfinished(QNetworkReply *reply5); //对应 QNetworkAccessManager 的 finish信号
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void on_pushButton_3_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
request1.setUrl(path+"01");
request2.setUrl(path+"02");
request3.setUrl(path+"03");
connect(&m_pManager1,&QNetworkAccessManager::finished,this,&MainWindow::m_pManagerfinished);
// [signal] void QNetworkAccessManager::finished(QNetworkReply *reply)
connect(&m_pManager2,&QNetworkAccessManager::finished,this,&MainWindow::m_pManagerfinished);
connect(&m_pManager3,&QNetworkAccessManager::finished,this,&MainWindow::m_pManagerfinished);
//connect(reply1,&QNetworkReply::finished,this,&MainWindow::replyfinished);//这三行不能在这里写
//connect(reply2,&QNetworkReply::finished,this,&MainWindow::replyfinished);
//connect(reply3,&QNetworkReply::finished,this,&MainWindow::replyfinished);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::replyfinished()
{
QNetworkReply* reply4 = (QNetworkReply*)sender();
qDebug()<<"reply--"<<reply4->readAll();
reply4->deleteLater();//关键步骤
}
void MainWindow::m_pManagerfinished(QNetworkReply *reply5)
{
qDebug()<<"m_pManager--"<<reply5->readAll();
reply5->deleteLater();//关键步骤
}
void MainWindow::on_pushButton_clicked()
{
reply1 = m_pManager1.post(request1,"");
connect(reply1,&QNetworkReply::finished,this,&MainWindow::replyfinished);
//[signal] void QNetworkReply::finished()
//指针赋值后才能connect
}
void MainWindow::on_pushButton_2_clicked()
{
reply2 = m_pManager2.post(request2,"");
connect(reply2,&QNetworkReply::finished,this,&MainWindow::replyfinished);
}
void MainWindow::on_pushButton_3_clicked()
{
reply3 = m_pManager3.post(request3,"");
connect(reply3,&QNetworkReply::finished,this,&MainWindow::replyfinished);
}
上面是两种删除的做法,经测试都可以,下面详细分开说明:
1、QNetworkAccessManager::finished
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
request1.setUrl(path+"01");
connect(&m_pManager1,&QNetworkAccessManager::finished,this,&MainWindow::m_pManagerfinished);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::m_pManagerfinished(QNetworkReply *reply5)
{
qDebug()<<"m_pManager--"<<reply5->readAll(); //读取内容
reply5->deleteLater(); //删除内存
}
void MainWindow::on_pushButton_clicked()
{
reply1 = m_pManager1.post(request1,"");
}
2、QNetworkReply::finished
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
request1.setUrl(path+"01");
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::replyfinished()
{
QNetworkReply* reply4 = (QNetworkReply*)sender();//多出的东西
qDebug()<<"reply--"<<reply4->readAll();//读取内容
reply4->deleteLater();//关键步骤
}
void MainWindow::on_pushButton_clicked()
{
reply1 = m_pManager1.post(request1,"");
connect(reply1,&QNetworkReply::finished,this,&MainWindow::replyfinished);
}
个人比较推荐第一种。
因为可能不注意写成下面的错误写法:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
request1.setUrl(path+"01");
connect(reply1,&QNetworkReply::finished,this,&MainWindow::replyfinished);//错误写法
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::replyfinished()
{
QNetworkReply* reply4 = (QNetworkReply*)sender();
qDebug()<<"reply--"<<reply4->readAll();
reply4->deleteLater();
}
void MainWindow::on_pushButton_clicked()
{
reply1 = m_pManager1.post(request1,"");
}
二、QNetworkReply::finished 与 QNetworkAccessManager::finished 的区别:
官方文档:
[signal] void QNetworkReply::finished()
答复完成处理后,将发出此信号。 发出此信号后,将不再对答复的数据或元数据进行任何更新。
除非已调用close()或abort(),否则仍将打开答复以进行读取,因此可以通过调用read()或readAll()来检索数据。 特别是,如果readyRead()的结果没有对read()的调用,则对readAll()的调用将检索QByteArray中的全部内容。
该信号与QNetworkAccessManager :: finished()串联发送,其中该信号的回复参数是此对象。
注意:请勿删除与此信号连接的插槽中的对象。 使用deleteLater()。
您还可以使用isFinished()来检查QNetworkReply是否已完成,甚至在您未收到finish()信号之前。
[signal] void QNetworkAccessManager::finished(QNetworkReply *reply)
每当待处理的网络回复结束时,都会发出此信号。 Reply参数将包含一个指向刚刚完成的回复的指针。 该信号与QNetworkReply :: finished()信号一起发射。
有关该对象将处于的状态的信息,请参见QNetworkReply :: finished()。
注意:请勿删除连接到该信号的插槽中的回复对象。 使用deleteLater()。