使用 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
)
我有以下 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
)