我有以下用例(实际上没有意义,因为它是从现实生活中的工作示例中最小化的,但我认为它在技术上仍然是正确的):
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
的内容,但仅当主窗口的标志被修改时。下面是MainWindow
类的代码,它使用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();
}
所有行似乎都是重现崩溃的必要条件。
这是一个bug在Qt,还是我做错了什么?
允许手动删除小部件的子组件,并且它们应该自动从父组件注销,如下面的手册引用所示。在我的实际案例中,小部件被删除以从GUI中消失,并且它适用于其他小部件组合。正如上面的评论所指出的,将delete dialog;
更改为dialog->deleteLater();
没有帮助。
似乎有一个问题,在删除Q3ListView
实例从Qt的后台存储,这是堆栈跟踪:
QtGuid4.dll !QWidgetBackingStore::staticContents(QWidget * parent, const QRect &第499行c++
QWidgetBackingStore::sync() Line 1200 c++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++
(外部代码)QtCored4.dll !QEventDispatcherWin32:: procesvents (QFlags flags) Line 823 c++
QtGuid4.dll !QGuiEventDispatcherWin32::processEvents(QFlags flags) Line 1216 c++
QtCored4.dll !QEventLoop:: procesvents (QFlags flags) Line 150 c++
QtCored4.dll !QEventLoop::exec(QFlags flags) Line 204 c++
QCoreApplication::exec() Line 1227 c++qtguide .dll!QApplication::exec() Line 3824 c++
qt_bug.exe !main(int argc, char * * argv) 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的手册:
你也可以自己删除子对象,它们将自己从父对象中移除。
这个代码是有效的。
我们已经在Windows 7 (MSVC 2010 SP1, CL 16), Windows 8 (MSVC 2013 U4, CL 18)和Fedora 20 (GCC 4.8.3)上重现了这个问题。
我已经提交了一个bug报告。由于它涉及到库的旧版本,因此不希望修复它。
无论如何,我们正在陆续删除Qt3Support,所以每个人都被建议;)