对象销毁后的事件

时间:2018-08-21 13:32:12

标签: c++ qt4

在缓慢的嵌入式系统中,我遇到了一个奇怪的问题:

如果我足够快,我可以通过双击按钮使应用程序崩溃。

其背后的原因是,在该应用程序中,只要有人单击“确定”按钮,就会关闭一个窗口。然后,在与“ pressed()”信号链接的插槽中发生窗口破坏(如果使用“ clicked()”信号,也会发生崩溃)。现在发生的是,第一次按下按钮正在关闭窗口,并调用'deleteLater()。进行此操作时,将捕获第二次按钮按下并将其放置在事件队列中。稍后我从“销毁”信号中得到一条消息,该窗口不再存在,但不久之后应用程序崩溃,因为QT的事件处理程序是由事件队列中的鼠标按下事件触发的。由于此事件,他尝试访问已被删除的对象。

我已经尝试过将'QCoreApplication :: removePostedEvents(sender())放入'destroyed()'信号所调用的插槽中,但这没有任何区别。

我使用的QT版本是4.8.4。这可能在以后的版本中解决了吗?

这是崩溃时的堆栈跟踪:

0   QMetaObject::addGuard   qobject.cpp 400 0xd65390    
1   QPointer<QAbstractButton>::QPointer qpointer.h  60  0x774948    
2   QAbstractButtonPrivate::emitPressed qabstractbutton.cpp 561 0x771df8    
3   QAbstractButton::mousePressEvent    qabstractbutton.cpp 1098    0x773198    
4   QToolButton::mousePressEvent    qtoolbutton.cpp 709 0x804310    
5   QWidget::event  qwidget.cpp 8371    0x39cc90    
6   QAbstractButton::event  qabstractbutton.cpp 1082    0x7730cc    
7   QToolButton::event  qtoolbutton.cpp 1160    0x80594c    
8   QApplicationPrivate::notify_helper  qapplication.cpp    4562    0x347e88    
9   QApplication::notify    qapplication.cpp    4105    0x346144    
10  QCoreApplication::notifyInternal    qcoreapplication.cpp    946 0xd4df34    
11  QCoreApplication::sendSpontaneousEvent  qcoreapplication.h  234 0x34a9b8    
12  QETWidget::translateMouseEvent  qapplication_qws.cpp    3528    0x3cb73c    
13  QApplication::qwsProcessEvent   qapplication_qws.cpp    2974    0x3c9660    
14  QEventDispatcherQWS::processEvents  qeventdispatcher_qws.cpp    119 0x3d2468    
15  QEventLoop::processEvents   qeventloop.cpp  149 0xd4b4fc    
16  QEventLoop::exec    qeventloop.cpp  200 0xd4b690    
17  QCoreApplication::exec  qcoreapplication.cpp    1218    0xd4e6f0    
18  QApplication::exec  qapplication.cpp    3823    0x344fac    
19  main    main.cpp    650 0x21900c    

这是程序中正在发生的事情的简化的伪代码:

...
QWidget * m_pScreenW;
QSignalMapper * m_pMapper;
...

main()
{
    ....
    connect( m_pUiState, SIGNAL( guiButtonPressed( const QString &, const QString & ) ),
             m_pSetupController, SLOT( slotButtonActivated( const QString &, const QString & ) ) );
    ....
}


void raiseScreen(QObject* parent)
{
    if ( m_pScreenW )
    {
        qDebug() << "~~~DeleteLater of screen: " << m_pScreenW;
        m_pScreenW->deleteLater();
        m_pScreenW = 0;
    }
    m_pScreenW = createNewScreenWithButtonsOnIt(parent);
}


QWidget* createNewScreenWithButtonsOnIt(QObject* parent)
{
    ....
    m_pScreenW = new QWidget(parent);
    m_pMapper = new QSignalMapper(m_pScreenW);
    ....
    if(screenContainsButton()
    {
        QToolButton pTB = new QToolButton(m_pScreenW);
        qDebug() << "~~+Creating toolbutton..." << pTB;
        connect(pTB, SIGNAL(destroyed()), this, SLOT(slotButtonDestroyed()));
        connect( p_pW, SIGNAL( pressed( ) ), m_pMapper, SLOT( map() ) );

    }
    ...
    connect( m_pMapper, SIGNAL( mapped( const QString & ) ),
             this, SLOT( slotPreprocessGuiButton( const QString & ) ) );
    connect( m_pWidget, SIGNAL(destroyed(QObject*)),
            this, SLOT(slotWindowDestroyed(QObject*)));
    ....
}

void dngApp_c::slotWindowDestroyed(QObject* o)
{
    qDebug() << "~~~Window destroyed:" << o;
}

void layout_n::manager_c::slotButtonDestroyed(void)
{
    qDebug() << "~~~Toolbutton destroyed" << sender();
}

void dngApp_c::slotPreprocessGuiButton( const QString & p_strButton )
{
    emit guiButtonPressed( strButton, "GUI" );
}


void ui_n::setupController_c::slotButtonActivated( const QString & p_strButtonId, const QString & p_strContext )
{
    ....
    else if ( p_strButtonId == strButtonIdAbortImmediately )
    {
        //Do something time consuming here
        ....
        QTimer::singleShot( 0, this, SLOT( slotOpenNewWindow() ) );

    }
    ....

}

void ui_n::setupController_c::slotOpenNewWindow( void )
{
    raiseScreen(0);
}

此外,还安装了事件过滤器,以获取有关事件队列的其他信息:

appEventFilter_c::appEventFilter_c( dngApp_c * p_pApp ) :
    QObject( p_pApp )
{
    ....
    p_pApp->installEventFilter( this );
}

bool appEventFilter_c::eventFilter( QObject * p_pObject, QEvent * p_pEvent )
{
    if ( p_pObject && p_pEvent )
    {
        switch ( p_pEvent->type() )
        {
 ....
        case QEvent::MouseButtonPress:
        ....
            qDebug() << "---Pressed!!";
            break;

        case QEvent::MouseButtonRelease:
        ....
            qDebug() << "---Released!!";
            break;

        default:
            break;
        }
    }
}

如果我双击QToolButton,则会在命令行中获得以下输出,最后一行是我获得的最后输出:

Line 38: ~~+Creating toolbutton... layout_n::toolButton_c(0x2365250)
Line 39: ~~+Creating toolbutton... layout_n::toolButton_c(0x22bc008)
Line 40: ~~+Creating toolbutton... layout_n::toolButton_c(0x22b5290)
Line 41: ~~+Creating toolbutton... layout_n::toolButton_c(0x22bdf90)
Line 43: ~~+Creating toolbutton... layout_n::toolButton_c(0x2432880)
Line 44: ~~+Creating toolbutton... layout_n::toolButton_c(0x23796a0)
Line 47: ~~+Creating toolbutton... layout_n::toolButton_c(0x2554b10)
Line 48: ~~~Toolbutton destroyed QObject(0x22c91a0)
Line 49: ~~~Toolbutton destroyed QObject(0x2412420)
Line 50: ~~~Toolbutton destroyed QObject(0x24123c0)
Line 51: ~~~Toolbutton destroyed QObject(0x2414a20)
Line 52: ~~~Toolbutton destroyed QObject(0x241ff50)
Line 53: ~~~Toolbutton destroyed QObject(0x241ff70)
Line 54: ~~~Window destroyed: QObject(0x2354cf0, name = "6 34:03.188")
Line 55: ~~~Toolbutton destroyed QObject(0x2554b10)
Line 56: ~~~Window destroyed: QObject(0x2498580)
Line 62: ~~+Creating toolbutton... layout_n::toolButton_c(0x254c038)
Line 63: ~~+Creating toolbutton... layout_n::toolButton_c(0x254d010)
Line 64: ~~~Toolbutton destroyed QObject(0x254c038)
Line 72: ---Pressed!!
Line 94: ---Released!!
Line 95: --DeleteLater of screen:  QWidget(0x235a2c0, name = "7 34:06.573")
Line 96: ~~+Creating toolbutton... layout_n::toolButton_c(0x25bdf90)
Line 97: ~~+Creating toolbutton... layout_n::toolButton_c(0x25bf7d0)
Line 98: ~~+Creating toolbutton... layout_n::toolButton_c(0x25c73d0)
Line 99: ~~+Creating toolbutton... layout_n::toolButton_c(0x25d1dc8)
Line 101: ~~+Creating toolbutton... layout_n::toolButton_c(0x25d72d0)
Line 106: ---Pressed!!
Line 107: ~~~Toolbutton destroyed QObject(0x2365250)
Line 108: ~~~Toolbutton destroyed QObject(0x22bc008)
Line 109: ~~~Toolbutton destroyed QObject(0x22b5290)
Line 110: ~~~Toolbutton destroyed QObject(0x22bdf90)
Line 111: ~~~Toolbutton destroyed QObject(0x2432880)
Line 112: ~~~Toolbutton destroyed QObject(0x23796a0)
Line 113: ~~~Toolbutton destroyed QObject(0x254d010)
Line 114: ~~~Window destroyed: QObject(0x231ec20)
Line 115: ~~~# Query: Trackdeletion PC Overlay
Line 116: ~~~Window destroyed: QObject(0x235a2c0, name = "7 34:06.573")

如果我现在进行堆栈跟踪,可以在第4级“ QToolButton :: mousePressEvent”处找到以下变量内容:

d    @0x24b6020 QToolButtonPrivate
e    @0xbea566ec    QMouseEvent
opt     QStyleOptionToolButton
this    "" @0x254d010   QToolButton

但是根据第113行已经删除了具有该地址的工具按钮,这导致程序崩溃。

1 个答案:

答案 0 :(得分:0)

有关更多信息,我现在在工具按钮被销毁的瞬间添加回溯记录:

0   layout_n::manager_c::slotButtonDeleted  layoutmanager.cpp   526 0x27eb70    
1   layout_n::manager_c::qt_static_metacall moc_layoutmanager.cpp   243 0x28a4b4    
2   QMetaObject::activate   qobject.cpp 3540    0xd6c2f0    
3   QObject::destroyed  moc_qobject.cpp 149 0xd6dce8    
4   QObject::~QObject   qobject.cpp 843 0xd66c3c    
5   QWidget::~QWidget   qwidget.cpp 1705    0x38be4c    
6   QAbstractButton::~QAbstractButton   qabstractbutton.cpp 608 0x77284c    
7   QToolButton::~QToolButton   qtoolbutton.cpp 409 0x803c48    
8   layout_n::toolButton_c::~toolButton_c   layoutmanager.h 185 0x28b934    
9   layout_n::toolButton_c::~toolButton_c   layoutmanager.h 185 0x28b994    
10  QObjectPrivate::deleteChildren  qobject.cpp 1908    0xd68368    
11  QWidget::~QWidget   qwidget.cpp 1681    0x38bd90    
12  QWidget::~QWidget   qwidget.cpp 1705    0x38bec8    
13  qDeleteInEventHandler   qobject.cpp 4270    0xd6d858    
14  QObject::event  qobject.cpp 1175    0xd67384    
15  QWidget::event  qwidget.cpp 8846    0x39e564    
16  QApplicationPrivate::notify_helper  qapplication.cpp    4566    0x348428    
17  QApplication::notify    qapplication.cpp    4530    0x348260    
18  QCoreApplication::notifyInternal    qcoreapplication.cpp    947 0xd4e6b4    
19  QCoreApplication::sendEvent qcoreapplication.h  231 0x34aee4    
20  QCoreApplicationPrivate::sendPostedEvents   qcoreapplication.cpp    1572    0xd4f950    
21  QCoreApplication::sendPostedEvents  qcoreapplication.cpp    1468    0xd4f548    
22  QCoreApplication::sendPostedEvents  qcoreapplication.h  236 0x3d2e68    
23  QEventDispatcherQWS::flush  qeventdispatcher_qws.cpp    164 0x3d2dbc    
24  QCoreApplication::flush qcoreapplication.cpp    683 0xd4e0d0    
25  QAbstractButton::mousePressEvent    qabstractbutton.cpp 1101    0x773910    
26  QToolButton::mousePressEvent    qtoolbutton.cpp 710 0x804a90    
27  QWidget::event  qwidget.cpp 8371    0x39d230    
28  QAbstractButton::event  qabstractbutton.cpp 1085    0x77384c    
29  QToolButton::event  qtoolbutton.cpp 1162    0x8060cc    
30  QApplicationPrivate::notify_helper  qapplication.cpp    4566    0x348428    
31  QApplication::notify    qapplication.cpp    4108    0x3466e4    
32  QCoreApplication::notifyInternal    qcoreapplication.cpp    947 0xd4e6b4    
33  QCoreApplication::sendSpontaneousEvent  qcoreapplication.h  234 0x34af58    
34  QETWidget::translateMouseEvent  qapplication_qws.cpp    3539    0x3cbe08    
35  QApplication::qwsProcessEvent   qapplication_qws.cpp    2984    0x3c9d48    
36  QEventDispatcherQWS::processEvents  qeventdispatcher_qws.cpp    121 0x3d2b5c    
37  QEventLoop::processEvents   qeventloop.cpp  149 0xd4bc7c    
38  QEventLoop::exec    qeventloop.cpp  200 0xd4be10    
39  QCoreApplication::exec  qcoreapplication.cpp    1221    0xd4eec8    
40  QApplication::exec  qapplication.cpp    3823    0x34551c    
41  main    main.cpp    650 0x2192b4    

您可以看到QWS系统在第34行附近捕获到了鼠标按键,然后蜂鸣到相应的按钮,按键应将该按钮绘制为按下状态(第25行)并刷新事件队列为了处理绘制事件,在这种情况下,它还会找到“上一步删除”(第13行),该事件已由上一个鼠标按键事件发布到事件队列中并执行此删除操作。退出flush函数后,它将继续对非法的指针变量进行操作,因为其自身的对象已被破坏