【问题标题】:Deleting a static class instance of QWidget type causes invalid pointer error删除QWidget类型的静态类实例导致无效指针错误
【发布时间】:2026-01-25 13:10:01
【问题描述】:

我试图通过子类化 QWidget 并导出一个静态类实例来创建一个单例类。但是,尝试删除此类实例会导致崩溃。为什么?

#include <QWidget>
#include <QApplication>

using namespace std;

class MyWidget : public QWidget
{
  public:
    static MyWidget *get_instance(){ static MyWidget instance; return &instance; };
};



int main
(
  int argc,
  char **argv
)
{
    QApplication app( argc, argv );
    MyWidget *widget = MyWidget::get_instance();

    QWidget *parent_widget = new QWidget;
    widget->setParent( parent_widget );
    delete parent_widget; //crashes 

    return app.exec();
}

运行上面的代码会产生以下错误消息。我没有包含 bakctrace 消息,该消息太长而无法在此帖子中显示。

QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-jon'
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-jon'
*** Error in `/home/shouheng/tmp/build-exp_main-Desktop_Qt_5_10_0_GCC_64bit-Debug/exp_main': free(): invalid pointer: 0x00000000006030c0 ***

【问题讨论】:

  • 我不确定你为什么对此感到困惑。当您调用 delete parent_widget 时,parent_widget 将递归删除其所有子代,依此类推。但是MyWidget::get_instance() 返回的小部件不是使用new 分配的——因此出现了错误。
  • 在删除 qobject 时使用 qt 方式:parent_widget-&gt;deleteLater() 而不是 delete parent_widget
  • @tunglt 这不会解决问题,因为它仍然会尝试delete 一个未在堆上分配的对象new
  • @tunglt 这只会将问题推迟到以后,更准确地说是when the event loop has started,但随后会出现完全相同的问题!

标签: c++ qt static qt5


【解决方案1】:

当您删除父小部件时,delete 将在其所有子部件上调用,因此在指向您的单例对象的指针上调用,该对象尚未使用 new 创建,即未在堆上分配:

static MyWidget instance; 

为了避免这种情况,只需 un-parent 单例对象,这样

widget->setParent(nullptr);

parent_widget 上调用 delete 之前。

【讨论】:

    【解决方案2】:

    Qt 与父级转移/处理所有权。

    所以当你这样做时

    widget->setParent( parent_widget );
    

    parent_widget 将删除其析构函数中的widget(除非其父级之前发生更改)。

    【讨论】: