未调用 QCoreApplication 析构函数
Posted
技术标签:
【中文标题】未调用 QCoreApplication 析构函数【英文标题】:QCoreApplication destructor is not called 【发布时间】:2014-04-25 12:34:59 【问题描述】:我有一个从QCoreApplication
类派生的应用程序,并且有一个子线程成员。当我删除应用程序对象时,它有时会删除,有时不会。
class My_class :public QCoreApplication
private:
My_object* obj;
QThread *th;
public:
My_class()
obj=new My_object();
th= new QThread();
obj->movetoThread(th); // so it starts to run
~My_class()
delete obj;
cout<<" App Destructor called"<<endl;
static void exit_()quit();
;
// So in main I suddenly close my application and i want to exit and delete obj;
int main()
My_class app;
signal(SIGTERM,&app.exit_);
signal(SIGINT,&app.exit_);
signal(SIGBREAK,&app.exit_);
return app.exec();
// The obj destructor is;
~My_object::My_object()cout<<"Object dest called"<<endl;
// The output of my program always writes "Object dest called"
//But sometimes writes " App Destructor called".
所以我的程序总是进入 obj 的 destructpr
,但有时它会进入 app 析构函数,有时不会。如何实现?
【问题讨论】:
我认为它确实指出了发布完整、独立、可编译的代码是多么非常重要。这样我们就不必在这样的愚蠢错误上浪费时间了。 @KubaOber 是的,你是对的 【参考方案1】:您可能有兴趣使用记录在 here 的应用程序销毁后例程。
在这种情况下,您可以注册一个 post 例程来清理您存储在给定集合中的所有线程:
QList<QThread*> myThreads;
static void cleanup_threads()
foreach (QThread thread, myThreads)
// cleanup the thread and delete it
int main(int argc, char **argv)
QCoreApplication app(argc, argv);
qAddPostRoutine(cleanup_threads);
// setup signal handlers
// create threads
return app.exec();
除非您确切知道自己在做什么,否则这种方法可能非常危险。首选方法是创建另一个派生自 QObject 的类,您可以将线程作为父级:
class MyThreadManager : public QObject
MyThreadManager(QObject *parent = 0)
: QObject(parent)
for (int i = 0; i < 5; ++i)
MyThread *thread = new MyThread(this);
// configure the thread object
thread->start();
// maybe add it to a local collection for later access:
// m_threads.append(thread);
;
int main(int argc, char **argv)
QCoreApplication app(argc, argv);
// setup signal handlers
MyThreadManager manager;
return app.exec();
这样,您的所有线程都成为同一个对象的父级,该对象在销毁时由父级的 QObjectCleanupHandler 清理。
【讨论】:
这是一种相当复杂的方法。 请注意@KubaOber,我正在使用发布的原始代码。他似乎想要跟踪线程,以及与这些线程关联的对象。在助手类中维护它不一定是一个坏主意。话虽如此,我想我认为您对我的回复的评论是没有正当理由的否定,因此不是很有帮助 原始代码的问题相当简单,不需要大量的设计更改。对象的竞争/不受保护的跨线程访问,仅此而已。【参考方案2】:您将obj
移动到另一个线程:
My_class()
obj=new My_object();
th= new QThread();
obj->movetoThread(th); // so it starts to run
一个QObject
只能从它的线程中删除,如果它有一个。因此,这段代码是错误的:
~My_class()
// You can't delete `obj` from a thread other than `th`!
delete obj;
cout<<" App Destructor called"<<endl;
你必须做的是先完成线程,然后才删除对象:
~My_class()
th->quit();
th->wait();
delete th;
Q_ASSERT(obj->thread() == NULL); // thus it's safe to delete obj now!
delete obj;
这可以自动完成。我认为没有理由将线程和对象保留在堆上。这是一种过早的悲观情绪。如果您打算在第一次使用时延迟构造对象及其线程,那么您应该使用智能指针:QScopedPointer
(或std::unique_ptr
,但不是 std::auto_ptr
)。
class Thread : public QThread
using QThread::run; // It's a final class
public:
explicit Thread(QObject * parent = 0) : QThread(parent)
~Thread() quit(); wait();
class My_Class : public QCoreApplication
My_Object m_obj;
Thread m_thread; // Must be declared after any objects that live in it.
public:
My_Class()
m_obj.moveToThread(&m_thread);
m_thread.start();
static void exit_() quit();
;
这是可行的,因为m_thread
将在m_obj
之前被破坏。您可以而且应该利用 C++ 编译器为您生成正确的代码。毕竟,编译器总是会做对的。
【讨论】:
以上是关于未调用 QCoreApplication 析构函数的主要内容,如果未能解决你的问题,请参考以下文章
如果调用 asio::strand 的析构函数时,该链上仍有一些就绪/未就绪的处理程序怎么办?
在 Visual Studio 中,与 std::async 一起使用时未调用“thread_local”变量的析构函数,这是一个错误吗?