简体   繁体   English

使用 QNetworkAccessManager 时智能指针和避免手动 memory 管理

[英]Smart pointers and avoid manual memory management when using QNetworkAccessManager

I have the following class which calls some HTTP API request to a server:我有以下 class 调用一些 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;
    }
};

I use the class in this way:我以这种方式使用 class:

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

Now this clearly involves some manual memory management and I have to be careful to not forget deleting the raw pointers.现在这显然涉及一些手动 memory 管理,我必须小心不要忘记删除原始指针。 I was wondering if the code above could be written using QSharedPointer (or even std::shared_ptr ) and replacing:我想知道是否可以使用QSharedPointer (甚至std::shared_ptr )编写上面的代码并替换:

        auto reply = m_netManager->get(request);

with:和:

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

then replace all instances of reply with smartReply.get() and then forget about manually deleting reply objects.然后用smartReply.get()替换所有reply实例,然后忘记手动删除回复对象。 However, it is unclear to me if the shared pointer will automatically delete the objects because between the time frame that I call send() and the signal QNetworkReply::finished , would the smart pointer know that the raw pointer is still in use?但是,我不清楚共享指针是否会自动删除对象,因为在我调用send()的时间范围和信号QNetworkReply::finished之间,智能指针会知道原始指针仍在使用中吗? Also when I delete an instance of NetworkRequest will the shared pointer automatically delete the QNetworkReply it owns?另外,当我删除NetworkRequest的实例时,共享指针会自动删除它拥有的QNetworkReply吗?

Ok so after some thinking I came up with a solution.好的,经过一番思考,我想出了一个解决方案。 The main problem I wanted to solve was to avoid deleting my QNetworkReply* object manually, instead I wanted it to be automatically destroyed when an instance of NetworkRequest is deleted.我想解决的主要问题是避免手动删除我的QNetworkReply* object,而是希望在删除NetworkRequest实例时自动销毁它。 In order to achieve this, I used a std::unique_ptr as a private member of my NetworkRequest class so when the class is destroyed, the unique_ptr automatically cleans the object in memory. In order to achieve this, I used a std::unique_ptr as a private member of my NetworkRequest class so when the class is destroyed, the unique_ptr automatically cleans the object in memory. Furthermore, by default std::unique_ptr deletes the object it hold upon reassignment, so whenever I call the send function in my, I can assign a new object to the smart pointer and the previous object in memory will get deleted automatically. Furthermore, by default std::unique_ptr deletes the object it hold upon reassignment, so whenever I call the send function in my, I can assign a new object to the smart pointer and the previous object in memory will get deleted automatically. One thing to notice, was the Qt docs recommend that QNetworkReply* should be deleted using QObject::deleteLater() (it is not fully clear to me why this is the case), in order to do this one can just use a custom deleter.需要注意的一件事是,Qt 文档建议使用QObject::deleteLater()删除QNetworkReply* (我不完全清楚为什么会这样),为了做到这一点,可以使用自定义删除器. So in my code, I declared a private member as following:所以在我的代码中,我声明了一个私有成员,如下所示:

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

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

    ReplyPointer m_reply;

Then in my send function:然后在我send function 中:

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

Obviously, in the signature of signal and slots I have to pass the raw pointer ( m_reply.get() ).显然,在信号和槽的签名中,我必须传递原始指针( m_reply.get() )。

( QSharedPointer can also be used instead of std::unique_ptr ) QSharedPointer也可以用来代替std::unique_ptr

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM