不调用QCoreApplication析构函数

时间:2014-04-25 12:35:00

标签: c++ c qt

我有一个派生自QCoreApplication类的应用程序,并且有一个子线程成员。当我删除app对象时,它有时会删除。

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析构函数,有时不会。怎么可以实现?

2 个答案:

答案 0 :(得分:0)

您可能有兴趣使用文档例程来记录应用程序销毁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清理。

答案 1 :(得分:0)

您将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,但 {{1} })。

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将被销毁。您可以而且应该利用C ++编译器为您生成正确的代码。毕竟,编译器总能正确使用它。