QNetworkAccessManager 在删除时崩溃
我有一个从 QObject 派生的类“Downloader”,它在工作线程中运行。当线程启动时,下载器在堆上创建一个QNetworkAccessManager对象,并开始请求文件。我跟踪已请求和收到的文件数量。获取所有文件后,我删除 QNetworkAccessManager 对象并退出线程。我的问题是,无论何时何地删除管理器对象都会导致崩溃。我什至尝试过 manager->deleteLater()。如果我不删除它,我的代码运行得很好,但我知道那里存在内存泄漏。这是我的代码的精简版本。
创建下载器和线程,并设置信号,以便启动线程开始下载,下载完成后,线程停止:
QThread thread;
Downloader downloader;
downloader.setFiles(files);
downloader.moveToThread(&thread);
downloader.connect(&thread, SIGNAL(started()), SLOT(downloadFiles()));
thread.connect(&downloader, SIGNAL(downloadsFinished()), SLOT(quit()));
thread.start();
下载器的实现:
void Downloader::downloadFiles()
{
QNetworkAccessManager *manager = new QNetworkAccessManager();
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(finished(QNetworkReply*)));
receivedCount = 0;
requestCount = files.count();
for (QStringList::const_iterator pos = files.begin(); pos != files.end(); ++pos)
{
QUrl url(*pos);
manager->get(QNetworkRequest(url));
}
}
void Downloader::finished(QNetworkReply *reply)
{
// *** Get the file data and process it *** //
++receivedCount;
reply->deleteLater();
if (receivedCount == requestCount)
{
// manager->deleteLater();
emit downloadsFinished();
}
}
注释掉的行将使应用程序崩溃。即使在下载器的析构函数中删除管理器,或将下载器设置为管理器的父级也会使应用程序崩溃。
我首先尝试将管理器创建为堆栈上的常规成员变量,但这样做会导致其自身的错误,因为管理器将在 GUI 线程中创建,然后尝试在不同的线程上创建子级。
在有人说“QNetworkAccessManager 是异步的。为什么在工作线程中使用它?”之前我有我的理由。做这样的事情不应该是闻所未闻的。
I have a class 'Downloader' derived from QObject that runs in a worker thread. When the thread is started, the downloader creates a QNetworkAccessManager object on the heap, and starts to request files. I keep track of how many files have been requested and received. Once I've gotten all of the files, I delete the QNetworkAccessManager object and exit the thread. My problem is that deleting the manager object causes a crash no matter when or where I do this. I've even tried manager->deleteLater(). If I don't delete it, my code runs great, but I know there is a memory leak there. Here is a stripped down version of my code.
Creating the downloader and thread, and setting signals up so that starting the thread starts the downloads, and when the downloads are complete, the thread stops:
QThread thread;
Downloader downloader;
downloader.setFiles(files);
downloader.moveToThread(&thread);
downloader.connect(&thread, SIGNAL(started()), SLOT(downloadFiles()));
thread.connect(&downloader, SIGNAL(downloadsFinished()), SLOT(quit()));
thread.start();
Implementation for the downloader:
void Downloader::downloadFiles()
{
QNetworkAccessManager *manager = new QNetworkAccessManager();
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(finished(QNetworkReply*)));
receivedCount = 0;
requestCount = files.count();
for (QStringList::const_iterator pos = files.begin(); pos != files.end(); ++pos)
{
QUrl url(*pos);
manager->get(QNetworkRequest(url));
}
}
void Downloader::finished(QNetworkReply *reply)
{
// *** Get the file data and process it *** //
++receivedCount;
reply->deleteLater();
if (receivedCount == requestCount)
{
// manager->deleteLater();
emit downloadsFinished();
}
}
The commented out line will crash the app. Even deleting the manager in Downloader's destructor, or setting the downloader as the manager's parent will crash the app.
I first tried creating the manager as a regular member variable on the stack, but doing so causes errors of it's own since the manager would be created in the GUI thread and later try to create children on a different thread.
And before anybody says "QNetworkAccessManager is asynchronous. Why use it in a worker thread?" I have my reasons. It shouldn't be THAT unheard of to do something like this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
唯一明显的问题在下面,但我不确定您是否已发布完整代码
您正在您的方法中创建一个 local
QNetworkAccessManager *manager
但不保留引用到它,然后尝试在 finish() 方法中访问它。您应该分配
new QNetworkAccessManager();
一个成员变量!The only obvious problem is below but I am not sure if you have posted your entire code or not
You are creating a local
QNetworkAccessManager *manager
in your method but not keeping a reference to it and then trying to access it within finished() method.You should assign
new QNetworkAccessManager();
a member variable !