【问题标题】:Smart pointers and avoid manual memory management when using QNetworkAccessManager使用 QNetworkAccessManager 时智能指针和避免手动内存管理
【发布时间】:2019-10-02 11:55:14
【问题描述】:

我有以下类调用一些 HTTP API 请求到服务器:

class NetworkRequest : public QObject {

public:
    NetworkRequest(QNetworkAccessManager* netManager):
        m_netManager(netManager){}

    void send(QUrl const &url){
        QNetworkRequest request(url);
        auto reply = m_netManager->get(request);
        connect(reply, &QNetworkReply::finished, [this, reply](){
            // do some stuff with reply (like if url is redirected)
            if(isRedirected(reply)){
                // we have to delete the reply and send a new one
                QUrl newUrl;
                // somehow get the new url;
                reply->deleteLater();
                send(newUrl);
            }
            else{
                reply->setParent(this); // so that it will be deleted when an instance of this class is deleted
                emit completed(reply);
            }
        });
    }

signals:
    void completed(QNetworkReply* reply);

private:
    QNetworkAccessManager* m_netManager;
    bool isRedirected(QNetworkReply * reply){
        bool yes = false;

        /* process the process reply and determine yes is true or false
        ....
        **/
        return yes;
    }
};

我是这样使用类的:

auto req = new NetworkRequest(nm);
req->send("http://someurl.com");
connect(req, &NetworkRequest::completed, randomClass, &RandomClass::slot);

// in RandomClass::slot I call NetworkRequest::deleteLater() when I finished with the network data

现在这显然涉及一些手动内存管理,我必须小心不要忘记删除原始指针。我想知道是否可以使用QSharedPointer(甚至std::shared_ptr)编写上面的代码并替换:

        auto reply = m_netManager->get(request);

与:

        auto smartReply = QSharedPointer<QNetworkReply>(m_netManager->get(request));

然后用smartReply.get() 替换所有reply 实例,然后忘记手动删除回复对象。但是,我不清楚共享指针是否会自动删除对象,因为在我调用send() 和信号QNetworkReply::finished 之间,智能指针会知道原始指针仍在使用中吗?另外,当我删除NetworkRequest 的实例时,共享指针会自动删除它拥有的QNetworkReply 吗?

【问题讨论】:

  • Qt 文档说,您应该删除回复,但不是直接在插槽中,而是使用deleteLater()。看起来您在代码中正确执行了此操作。
  • @vahancho 那么可以使用带有自定义删除器的QSharedPointer 吗? (doc.qt.io/qt-5/qsharedpointer.html#QSharedPointer-2)
  • 它可能会被使用,但我没有看到使用共享指针的意义。谁分享指针?在这种情况下,作用域或唯一指针将更合适,IMO。
  • 但是在QNetworkReply::finished 发出之前范围不会结束吗?
  • 范围是send() 函数。但无论如何,我不会使用智能指针来管理不是由我创建的指针的生命周期。

标签: c++ qt smart-pointers signals-slots qsharedpointer


【解决方案1】:

好吧,经过一番思考,我想出了一个解决方案。我想解决的主要问题是避免手动删除我的QNetworkReply* 对象,而是希望在删除NetworkRequest 的实例时自动销毁它。为了实现这一点,我使用了std::unique_ptr 作为我的NetworkRequest 类的私有成员,所以当类被销毁时,unique_ptr 会自动清理内存中的对象。此外,默认情况下std::unique_ptr 会在重新分配时删除它持有的对象,所以每当我在我的函数中调用send 函数时,我可以为智能指针分配一个新对象,并且内存中的前一个对象将被自动删除。需要注意的一件事是,Qt 文档建议应该使用 QObject::deleteLater() 删除 QNetworkReply*(我不完全清楚为什么会这样),为了做到这一点,可以使用自定义删除器。 所以在我的代码中,我声明了一个私有成员如下:

private:
    struct deleteLaterDeletor
    {
        void operator()(QObject *object) const
        {
            if(object) {
                object->deleteLater();
            }
        }
    };

    using ReplyPointer = std::unique_ptr<QNetworkReply, deleteLaterDeletor>;

    ReplyPointer m_reply;

然后在我的send 函数中:

        m_reply = ReplyPointer(mNetManager->get(netRequest));

显然,在信号和槽的签名中,我必须传递原始指针 (m_reply.get())。

(也可以用QSharedPointer代替std::unique_ptr

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-02
    • 2010-10-22
    • 1970-01-01
    • 2012-05-12
    • 1970-01-01
    • 2013-12-23
    • 2017-04-03
    • 1970-01-01
    相关资源
    最近更新 更多