Q3ListView 是否无法从 Qt 后备存储中注销或代码错误?

Does Q3ListView fail to unregister from Qt backing store or the code is wrong?

我有以下用例(实际上没有意义,因为它是从现实生活中的工作示例中最小化的,但我认为它在技术上仍然是正确的):

class Dialog : public QDialog
{
public:
  Dialog(QWidget* parent)
    : QDialog(parent)
    {
      new Q3ListView(this); // this will crash
//    new QWidget(this);    // this won't crash
    }
};

根据添加到 Dialog 的内容,程序在删除 Dialog 实例时是否会崩溃(如代码段中的注释所示),但仅当 main window 的标志已被修改。这是 MainWindow class 的代码,它使用 Dialog:

class MainWindow : public QMainWindow
{
public:
  // the fact that the widget (dialog) below 
  // has no chance to show seems irrelevant. 
  // In the real scenario I have, the widget is shown on 
  // the screen and is closed by the user. 
  // I've just put the whole sequence of pieces of code 
  // that result from signal/slot calls, that in turn 
  // result from a point&click scenario in our application 
  // into the following function for brevity.
  void go()
    {        
      auto dialog = new Dialog(this);
      dialog->show();
      dialog->close();
      
      disableAlwaysOnTop();

      delete dialog; // or dialog->deleteLater();
    }

  void disableAlwaysOnTop()
    {
      setAttribute(Qt::WA_Resized, true);

      Qt::WindowFlags flags = windowFlags();
      setWindowFlags(flags ^ (Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint));

      setVisible(true);
    }
};

main的执行:

int main(int argc, char** argv)
{
  QApplication app(argc, argv);
  MainWindow mainWindow;
  mainWindow.show();
  mainWindow.go();
  return app.exec();
}

所有行似乎都是重现崩溃所必需的。

是Qt的bug,还是我做错了什么?

允许手动删除小部件的子项,并且它们应该自动从其父项中注销,如下面手册中的引述所示。在我的真实案例中,小部件被删除以从 GUI 中消失,并且它适用于其他小部件组合。如上面的评论所示,将 delete dialog; 更改为 dialog->deleteLater(); 没有帮助。

似乎从 Qt 的后备存储中删除 Q3ListView 实例时出现问题,这里是堆栈跟踪:

QtGuid4.dll!QWidgetBackingStore::staticContents(QWidget * parent, const QRect & withinClipRect) Line 499 C++

QtGuid4.dll!QWidgetBackingStore::sync() Line 1200 C++

QtGuid4.dll!QWidgetPrivate::syncBackingStore() Line 1896 C++

QtGuid4.dll!QWidget::event(QEvent * event) Line 8694 C++

QtGuid4.dll!QMainWindow::event(QEvent * event) Line 1479 C++

QtGuid4.dll!QApplicationPrivate::notify_helper(QObject * receiver, QEvent * e) Line 4565 C++

QtGuid4.dll!QApplication::notify(QObject * receiver, QEvent * e) Line 4530 C++

QtCored4.dll!QCoreApplication::notifyInternal(QObject * receiver, QEvent * event) Line 955 C++

QtCored4.dll!QCoreApplication::sendEvent(QObject * receiver, QEvent * event) Line 231 C++

QtCored4.dll!QCoreApplicationPrivate::sendPostedEvents(QObject * receiver, int event_type, QThreadData * data) Line 1579 C++

QtCored4.dll!qt_internal_proc(HWND__ * hwnd, unsigned int message, unsigned __int64 wp, __int64 lp) Line 498 C++

[External Code]

QtCored4.dll!QEventDispatcherWin32::processEvents(QFlags flags) Line 823 C++

QtGuid4.dll!QGuiEventDispatcherWin32::processEvents(QFlags flags) Line 1216 C++

QtCored4.dll!QEventLoop::processEvents(QFlags flags) Line 150 C++

QtCored4.dll!QEventLoop::exec(QFlags flags) Line 204 C++

QtCored4.dll!QCoreApplication::exec() Line 1227 C++

QtGuid4.dll!QApplication::exec() Line 3824 C++

qt_bug.exe!main(int argc, char * * argv) Line 60 C++

以及在堆栈跟踪中指示的行中尝试使用指向已删除对象的指针的 Qt 代码片段:

for (int i = 0; i < count; ++i) {
    QWidget *w = staticWidgets.at(i);
    QWidgetPrivate *wd = w->d_func();
    if (!wd->isOpaque || !wd->extra || wd->extra->staticContentsSize.isEmpty()  // ****
        || !w->isVisible() || (parent && !parent->isAncestorOf(w))) {
        continue;
    }

wd 指向在注释标记的行删除的对象)。

免责声明: 我知道存在更优雅的解决方案,但这是遗留代码,根据 Qt's manual:

You can also delete child objects yourself, and they will remove themselves from their parents.

此代码有效。

我们在 Windows 7(MSVC 2010 SP1,CL 16),Windows 8(MSVC 2013 U4,CL 18)和 Fedora 20(GCC 4.8.3)上重现了这个问题.

我已经提交了 bug report。由于它涉及旧版本的库,因此不希望它被修复。

无论如何,我们都会陆续删除 Qt3Support,建议大家这样做 ;)