qt QNetworkAccessManager QNetworkReply 内存泄露

  QT的QNetworkAccessManagerQNetworkReply使用时应注意内存泄露问题。

  原因在于他们收到的内容是个指针指向的内存,需要我们手动 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()。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值