QWidget析构函数存在的缺陷

这个问题是在上一篇处理程序无响应的时候发现的,背景就不说了。在处理完跨线程操作对象的问题后,发现仍然有小概率出现无响应现象,经过检测,和处理之前一样的现象,QPointer中保存的QObject(准确的说是保存的QWidget)对象指针存在,他的d_ptr却变成了NULL,也就是说变成了野指针。

 

QPointer开始保存对象的时候添加检测,发现在出现野指针之前有下面的堆栈:

QWidget析构函数存在的缺陷_第1张图片

从这里可以看到,在QWidget的析构函数里面调用了 DestroyWindow函数,该函数的他会清空线程的消息队列,所以调用到了WndProc。 如果消息队列中存在一个消息,在这个消息处理中使用了QPointer来保存QWidget会不会存在问题呢?分析一下,有两种情况:

 

1.保存的对象在本次析构完成前使用:此时的QWidget对象还没有销毁,所以使用中是不应该出现问题的。

 

2.保存的对象在析构以后调用:此时QWidget的基类QObject还没有开始析构,在QWidget析构完成时,QObject开始析构,他会标记QPointer中的对象为空,也不应该存在问题。

 

问题确实存在,继续查看代码实现:

QWidget析构函数存在的缺陷_第2张图片

这里有个判断widget,看来clearGuards在QWidget中有单独处理,查看QWidget的代码,确实在DestroyWindow之前就做了clearGuards,在这里说一下clearGuards的作用:QPointer保存了一个QObject的指针,并把这个指针的指针交给全局变量GuardHash管理,而QObject 在销毁时会调用clearGuards函数来把全局 GuardHash 的那个指针置为零,因此所有QPointer中保存的这个指针都为空。在这里先调用了clearGuards,然后在DestroyWindow中消息循环时再去保存的QPointer,在DestroyWindow执行完,QObject析构的时候就不会再去理会GuardHash的问题,此时导致存在QPointer中的对象变成了野指针。

 

到这里问题比较明了了,在QWidget::~QWidget()析构时处理的消息,为了保证窗口的安全操作,提前clearGuards,如果存在QPointer保存控件对象的操作,都有可能导致QPointer中野指针的出现



你可能感兴趣的:(QT)