You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qt应用正确终止方法:解决销毁MainWidget时的段错误问题

Qt对象销毁导致段错误的解决方案

问题根源

  1. 双重释放触发段错误:
    MainWidget是无父对象的顶级窗口,Qt默认在用户关闭窗口时会自动调用deleteLater()销毁该对象。此时Gui类里的mainWidget指针已变成野指针,当Gui析构时再执行delete mainWidget,就会触发双重释放,直接导致段错误。
  2. 子对象重复销毁隐患:
    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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 06:15:19