对 QMainWindow 使用 std::unique_ptr 时退出时出现 QT 应用程序分段错误
QT Application segmentation fault on exit when using std::unique_ptr for the QMainWindow
我应该首先澄清一下,我的问题是,为什么在我使用std::unique_ptr
的情况下会发生段错误,但当我更改代码以使用 new 和删除时却没有?我在这里真的没有问题,因为段错误已修复,并且我知道我正在用新的和删除正确清理内容。我只想知道为什么我不能使用std::unique_ptr
.
如果我在std::unique_ptr
中创建我的QMainWindow
实例,并且我的MainWindow
创建了一个子窗口(例如打开QComboBox
或ToolTip
),我的应用程序将在退出时出现段错误。在这种情况下,如果我的MainWindow
没有创建任何子窗口,则不存在段错误。
如果我自己使用 new 和 delete 管理我的QMainWindow
实例,则无论我是否创建子窗口,都没有段错误。
这是我的主要,它只是在我的Bridge
类上调用run
,该类处理创建我的MainWindow
类的实例并启动它。
int main(int argc, char *argv[])
{
Bridge bridge(argc, argv);
bridge.run(); // Handles starting the main window
}
这是我的Bridge
类的缩短版本,导致段错误(使用 std::unique_ptr 我在退出时得到段错误):
class Bridge::IMPL {
public:
IMPL(int& argc, char ** argv) :
mainwindow(), isRunning(true), app(argc, argv) {}
~IMPL() = default;
public:
std::unique_ptr<MainWindow> mainwindow;
bool isRunning;
QApplication app;
};
Bridge::Bridge(int& argc, char ** argv) :
pImpl(make_unique<IMPL>(argc, argv)) {
pImpl->mainwindow.reset(new MainWindow(this));
}
这是没有段错误的 Bridge 类(稍作修改以删除std::unique_ptr
,而是使用 new 和 delete。此版本的Bridge
类不会崩溃):
class Bridge::IMPL {
public:
IMPL(int& argc, char ** argv) :
mainwindow(nullptr), isRunning(true), app(argc, argv) {}
~IMPL() {
if (mainwindow) {
delete mainwindow;
}
}
public:
MainWindow* mainwindow;
bool isRunning;
QApplication app;
};
Bridge::Bridge(int& argc, char ** argv) :
pImpl(make_unique<IMPL>(argc, argv)) {
pImpl->mainwindow= new MainWindow(this);
}
这是发生段错误时的回溯:
还有一个关于QBasicTimer
的奇怪打印输出,在我将代码更改为使用 new 和 delete 而不是std::unique_ptr
QBasicTimer::start: QBasicTimer can only be used with threads started with QThread
Thread 1 "application" received signal SIGSEGV, Segmentation fault.
0x00007fffe75bf2e2 in ?? () from /home/user/Qt/5.9/gcc_64/plugins/platforms/../../lib/libQt5XcbQpa.so.5
(gdb) bt
#0 0x00007fffe75bf2e2 in ?? () from /home/user/Qt/5.9/gcc_64/plugins/platforms/../../lib/libQt5XcbQpa.so.5
#1 0x00007fffe75bf5c4 in ?? () from /home/user/Qt/5.9/gcc_64/plugins/platforms/../../lib/libQt5XcbQpa.so.5
#2 0x00007fffe75b9669 in QXcbConnection::removeWindowEventListener(unsigned int) () from /home/user/Qt/5.9/gcc_64/plugins/platforms/../../lib/libQt5XcbQpa.so.5
#3 0x00007fffe75ceafa in QXcbWindow::destroy() () from /home/user/Qt/5.9/gcc_64/plugins/platforms/../../lib/libQt5XcbQpa.so.5
#4 0x00007fffe75cec07 in QXcbWindow::~QXcbWindow() () from /home/user/Qt/5.9/gcc_64/plugins/platforms/../../lib/libQt5XcbQpa.so.5
#5 0x00007fffe43ce2ee in ?? () from /home/user/Qt/5.9/gcc_64/plugins/xcbglintegrations/libqxcb-glx-integration.so
#6 0x00007ffff4b56f46 in QWindowPrivate::destroy() () from /home/user/Qt/5.9/gcc_64/lib/libQt5Gui.so.5
#7 0x00007ffff534ecd7 in QWidgetPrivate::deleteTLSysExtra() () from /home/user/Qt/5.9/gcc_64/lib/libQt5Widgets.so.5
#8 0x00007ffff53524d8 in QWidget::destroy(bool, bool) () from /home/user/Qt/5.9/gcc_64/lib/libQt5Widgets.so.5
#9 0x00007ffff53598b0 in QWidget::~QWidget() () from /home/user/Qt/5.9/gcc_64/lib/libQt5Widgets.so.5
#10 0x00007ffff541ae7a in ?? () from /home/user/Qt/5.9/gcc_64/lib/libQt5Widgets.so.5
#11 0x00007ffff4580b83 in QObjectPrivate::deleteChildren() () from /home/user/Qt/5.9/gcc_64/lib/libQt5Core.so.5
#12 0x00007ffff5359894 in QWidget::~QWidget() () from /home/user/Qt/5.9/gcc_64/lib/libQt5Widgets.so.5
#13 0x00007ffff540eac9 in QComboBox::~QComboBox() () from /home/user/Qt/5.9/gcc_64/lib/libQt5Widgets.so.5
#14 0x00007ffff4580b83 in QObjectPrivate::deleteChildren() () from /home/user/Qt/5.9/gcc_64/lib/libQt5Core.so.5
#15 0x00007ffff5359894 in QWidget::~QWidget() () from /home/user/Qt/5.9/gcc_64/lib/libQt5Widgets.so.5
#16 0x00007ffff5359ab9 in QWidget::~QWidget() () from /home/user/Qt/5.9/gcc_64/lib/libQt5Widgets.so.5
#17 0x00007ffff4580b83 in QObjectPrivate::deleteChildren() () from /home/user/Qt/5.9/gcc_64/lib/libQt5Core.so.5
#18 0x00007ffff5359894 in QWidget::~QWidget() () from /home/user/Qt/5.9/gcc_64/lib/libQt5Widgets.so.5
#19 0x00007ffff5359ab9 in QWidget::~QWidget() () from /home/user/Qt/5.9/gcc_64/lib/libQt5Widgets.so.5
#20 0x00007ffff4580b83 in QObjectPrivate::deleteChildren() () from /home/user/Qt/5.9/gcc_64/lib/libQt5Core.so.5
#21 0x00007ffff5359894 in QWidget::~QWidget() () from /home/user/Qt/5.9/gcc_64/lib/libQt5Widgets.so.5
#22 0x0000000000421ed4 in MainWindow::~MainWindow() ()
#23 0x0000000000421f0e in MainWindow::~MainWindow() ()
#24 0x0000000000421698 in std::default_delete<MainWindow>::operator()(MainWindow*) const ()
#25 0x0000000000421171 in std::unique_ptr<MainWindow, std::default_delete<MainWindow> >::~unique_ptr() ()
#26 0x000000000042191c in Bridge::IMPL::~IMPL() ()
#27 0x0000000000421942 in std::default_delete<Bridge::IMPL>::operator()(Bridge::IMPL*) const ()
#28 0x0000000000421387 in std::unique_ptr<Bridge::IMPL, std::default_delete<Bridge::IMPL> >::~unique_ptr() ()
#29 0x0000000000420cb0 in Bridge::~Bridge() ()
#30 0x0000000000421c41 in main ()
还应该注意的是,此QApplication
是使用 while 循环和调用app.processEvents()
而不是调用exec()
运行的。我意识到这不是最好的方法,但是这个应用程序是另一个应用程序的一部分,该应用程序从其他地方轮询事件,并且由于该应用程序的性质比其他任何东西都更"概念验证",我想通过将其全部放在一个线程中来保持简单。请参阅下面的运行方法片段:
while (isRunning()) {
poller.poll(25);
app.processEvents();
}
编辑:
在我的构造函数中,MainWindow
我传递的this
没有设置为父级(父级nullptr
):
页眉:
class MainWindow: public QMainWindow
{
Q_OBJECT
public:
class BridgeInterface{
public:
// Some pure virtual methods here
};
explicit MainWindow(BridgeInterface* interface, QWidget* parent = nullptr);
// some more stuff...
private:
class IMPL;
std::unique_ptr<IMPL> pImpl;
};
源:
MainWindow::MainWindow(BridgeInterface* interface, QWidget* parent) :
QMainWindow(parent), pImpl(make_unique<IMPL>()) {
pImpl->ui->setupUi(this);
pImpl->bridgeInterface = interface;
// Connect slots and stuff
}
删除实例后不要删除MainWindow
QApplication
。您需要以某种方式管理初始化和销毁顺序。
QApp::ctor Window::ctor Window::dtor QApp::dtor
可能的解决方案:直接在Bridge::~Bridge
内销毁MainWindow
附言您不需要通过引用传递int argc
。
P.P.S. 关于 processEvents() - 你可以创建一个单独的线程并在那里运行你的 Qt 部分。使用GUI而不是从主线程,ofc,如果你知道,你在做什么:)。主规则 - QApplication 实例和所有 GUI 应从一个线程创建
在你的类中,QApplication 的析构函数在主窗口被销毁之前被调用。这是因为类变量是按照它们列出的顺序启动的,然后以相反的顺序销毁。
如果你移动QApplication app;
所以它是类中的第一个变量,它的析构函数将被调用 last,在主窗口被销毁之后,这是正确的行为。
显式删除它时它起作用的原因是您通过 IMPL 的析构函数删除mainwindow
。 ~IMPL() 在类变量析构函数运行之前运行,导致主窗口首先被销毁。
很难确定,因为您没有发布MainWindow的代码,但我会说您要删除主窗口两次。
pImpl->mainwindow= new MainWindow(this);
如果this
是父窗口,它将在销毁时自动删除主窗口,同样的事情将执行unique_ptr
要么使用原始指针并依赖Qt的父子清理,要么使用智能指针而不将父指针传递给MainWindow
。- QT在错误的班级中寻找空位
- libssh 的函数在构建 libssh 时无法在 Qt 和 cmake 错误中找到
- 错误-我无法在VS2019中打开新的Qt项目
- 将QT项目导入Visual Studio 2019会给我带来很多LNK2001错误
- Qmake 错误:QT: 图表中的未知模块
- 项目错误:QT中的未知模块:Mac上的图表
- 编译错误 QT - 无法从类型强制转换
- 未知类型名称错误 Qt C++
- LNK2001带有静态属性和方法的错误(QT,C )
- 数据库未打开错误QT C
- 当我用口音保存JSON时,我的文字错误(QT)
- C 错误:: -1:错误:QT-CREATOR中未找到架构X86_64的符号(S)
- 键按下事件错误 Qt 实现函数时
- Qt 5测试版2,Qt Creator 2.6,MSVC错误:Qt Creaator需要一个编译器来构建.在工具包选项中
- 在Windows 8下使用Tbb构建错误Qt创建器
- 项目错误:QT 中的未知模块:webkitwidgets
- 链接错误-Qt Creator OpenCV Ubuntu
- 项目错误:QT中的未知模块:蓝牙
- 1.项目错误:QT: webkitwidgets中的未知模块
- 找不到错误 QT