Qt应用正确终止方法:解决销毁MainWidget时的段错误问题
Qt对象销毁导致段错误的解决方案
问题根源
- 双重释放触发段错误:
MainWidget是无父对象的顶级窗口,Qt默认在用户关闭窗口时会自动调用deleteLater()销毁该对象。此时Gui类里的mainWidget指针已变成野指针,当Gui析构时再执行delete mainWidget,就会触发双重释放,直接导致段错误。 - 子对象重复销毁隐患:
MainWidget里的timer是用new QTimer(this)创建的,已经被设置为MainWidget的子对象。Qt的父子对象机制会在父对象销毁时自动销毁所有子对象,你在MainWidget析构里手动delete timer,会导致Qt再次销毁时出现重复释放问题。
修复步骤
1. 处理MainWidget的自动销毁问题(二选一即可)
方案A:禁止窗口自动销毁
在MainWidget的构造函数中添加代码,关闭窗口时不自动销毁对象:
MainWidget::MainWidget(QWidget *parent) : QWidget(parent) { setWindowModality(Qt::ApplicationModal); // 关闭窗口自动销毁属性 setAttribute(Qt::WA_DeleteOnClose, false); timer = new QTimer(this); connect(timer, &QTimer::timeout, this, &MainWidget::onTimeChanged); timer->start(1000); cardLabel = new QLabel(); cardLabel->setAlignment(Qt::AlignRight|Qt::AlignTop); cardLabel->setPixmap(QPixmap(":/icons/img")); }
修改后Gui的析构函数可以安全执行delete mainWidget。
方案B:监听窗口销毁信号,避免野指针
在Gui的构造函数中添加信号连接,当MainWidget被销毁时将指针置空:
Gui::Gui() { led = new Led(); mainWidget = new MainWidget(); mainWidget->show(); connect(this, SIGNAL(sendOneSignal()), mainWidget, SLOT(slotFunc())); // 监听销毁信号,清空指针 connect(mainWidget, &QObject::destroyed, this, [this](){ mainWidget = nullptr; }); }
然后修改Gui的析构函数,判断指针非空再删除:
Gui::~Gui() { delete led; if (mainWidget) { delete mainWidget; } }
2. 修正MainWidget的析构函数
移除手动删除timer的代码,让Qt父子机制自动处理:
MainWidget::~MainWidget() { timer->stop(); // 可省略,销毁timer时会自动停止 // 移除delete timer; 子对象由Qt自动销毁 delete cardLabel; // 若给cardLabel设置父对象(如new QLabel(this)),这行也可省略 }
3. 额外建议
尽量利用Qt的父子对象机制管理动态创建的对象,减少手动new/delete操作;或者使用Qt智能指针QScopedPointer/QSharedPointer,进一步规避内存管理问题。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

