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

Smart pointers and avoid manual memory management when using QNetworkAccessManager

我有以下 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;
    }
};

我是这样使用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

现在这显然涉及一些手动内存管理,我必须小心不要忘记删除原始指针。我想知道上面的代码是否可以使用 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 吗?

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

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)