2012.5.24
这两天才意识到自己的编程不规范的问题有多么严重。用Qt做了个widget,当主widget退出时,先后发现以下几种问题:
1、打开资源管理器,发现程序对应的进程还在并没有退出,当时猜想会不会是因为资源泄漏(觉得不应该,就算有内存泄露,进程退出后也应该释放)或者是因为双线程里的次线程没有退出(次线程属于主线程,主线程退出,次线程也应该退出吧),所以我就又做了个简单的demo,依次查看下资源释放以及次线程是否有问题;
2、很多资料上都讲,在新建一个对象时若指定它的父对象,则父对象删除时也一并删除子对象(是用delete删除的)。那么我就测试了下在主widget退出时是否会调用两个子widget的析构函数。测试结果是确实是这样。可是在我原来的那个程序里,子widget的析构函数却没有调用;
3、我重新看了下自己的程序,发现在各个类析构时存在问题。这时我脑海中浮现出那几条准则:线程对象在销毁之前一定要销毁从属于自己线程的那些对象;在调用quit终止一个次线程时一定要wait一下,等次线程完全终止执行。balabala好几条,根据这些原则,修改了下源程序,发现以前那个进程无法终止的情况有所好转:退出程序后观测任务管理器,进程还在,大约持续10s不到的时间进程会退出,但是之前windows会启动一个显示错误的进程,而且qt程序的exec返回码也不是0而是一长串看起来很虐心的数,还是有问题。
4、通过不断地测试程序和demo,神奇的发现如果在类的数据成员中定义类指针而不是类对象,似乎问题就解决了,可是这是为什么呢?当然如果我之前严格按照编程规范来写(为了减少编译依赖也得这样啊)大概就不会遇见这个问题了,可是既然有问题出现就得去面对去查找原因。
5、终于,我发现了自己犯了一个很幼稚的问题。在一个Worker类里我定义了一个QUdpSocket类的指针,由于想在次线程里新建指针所指对象,所以在worker的构造函数里这个指针并没有初始化,而且最为严重的是这个指针并没有指向一个堆上的对象,然而我却在Worker的析构函数里delete这个指针了。解决方案是:在构造函数里对指针初始化为0,在析构函数里先对指针进行判断,若不为0再进行删除操作。
教训:
1、一定要逻辑清晰,比如delete一个对象你就要想到它是在何时被new出来的。
2、在qt中删除一个对象最好用deletelater而不是delete,因为当你delete时事件队列里或许还有事件等着该对象处理,又或者该对象此时正在进行事件处理,不恰当时机的删除会使程序崩溃;
3、还是要严格遵守编程规范,否则出了问题再一个个排查太费劲。
4、指针问题果然还是运行时出错的一个主要问题啊