我有以下类,该类调用一些对服务器的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));
然后用reply
替换smartReply.get()
的所有实例,然后忘记手动删除回复对象。但是,我不清楚共享指针是否会自动删除对象,因为在我调用send()
的时间段和信号QNetworkReply::finished
之间,智能指针会知道原始指针仍在使用吗?另外,当我删除NetworkRequest
的实例时,共享指针会自动删除其拥有的QNetworkReply
吗?
好吧,经过一番思考,我想出了一个解决方案。我要解决的主要问题是避免手动删除QNetworkReply*
对象,而是希望在删除NetworkRequest
实例时将其自动销毁。为了实现此目的,我使用std::unique_ptr
作为我的NetworkRequest
类的私有成员,因此当销毁该类时,unique_ptr
自动清除内存中的对象。此外,默认情况下std::unique_ptr
会在重新分配时删除其持有的对象,因此,每当我在自己的计算机中调用send
函数时,都可以为智能指针分配一个新对象,并且内存中的先前对象会自动删除。需要注意的一件事是Qt docs建议使用QNetworkReply*
删除QObject::deleteLater()
(我尚不完全清楚为什么是这种情况),为了做到这一点,可以只使用自定义删除器。因此,在我的代码中,我声明了一个私有成员,如下所示:
private:
class deleteLaterDeletor
{
public:
template<typename T>
void operator()(T *reply) const
{
if(reply) {
reply->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
)