将成员控件设为QMainWindow中央控件为何未崩溃?
为什么将栈上的QGraphicsView设为QMainWindow中心部件后未出现双重删除崩溃?
代码示例
main.cpp
#include "main_window.hpp" #include <QtWidgets/QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }
main_window.hpp
#pragma once #include "ui_main_window.h" #include <QtWidgets/QMainWindow> #include <QGraphicsView> class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent) : QMainWindow(parent) { ui.setupUi(this); setCentralWidget(&view); } private: Ui::MainWindowClass ui; QGraphicsView view; };
疑问来源
Qt文档中关于QMainWindow::setCentralWidget的说明:
注意:QMainWindow会接管控件指针的所有权,并在适当时机将其删除。
按照这个逻辑,程序结束时view应该被Qt所有权机制和MainWindow的析构函数双重删除,但实际却没有崩溃,这是为什么?
原因解析
C++对象的析构顺序
当MainWindow对象w在main函数结束时被销毁,析构流程是:- 先执行
MainWindow的析构函数体(此处未自定义,故为空) - 按成员变量声明的逆序析构成员:先析构栈上的
view对象,再析构ui - 最后调用基类
QMainWindow的析构函数
- 先执行
Qt对象树的自动维护机制
QGraphicsView继承自QObject,当它被析构时,QObject的析构函数会自动将自身从父对象(即MainWindow)的子对象列表中移除。也就是说,在MainWindow的基类析构函数执行前,view已经被销毁,并且不再属于MainWindow的子对象集合。避免双重删除的关键
QMainWindow的析构函数只会遍历当前子对象列表,删除其中的对象。由于view已经提前从子列表中移除,基类析构函数不会再尝试删除它,因此不会出现“栈对象被delete”的未定义行为,自然也就不会崩溃。
内容的提问来源于stack exchange,提问作者qloq
相关产品推荐
相关产品推荐

