我正在使用Python& QT做一些实验。
我使用Python通过调用QT的函数来创建GUI应用程序
但是,当我关闭一个简单的GUI应用程序时,它引发了一个分段错误(核心转储)。
// This is python C++ extension
#ifndef QT_API
#define QT_API
#include "Python.h"
#include <QtWidgets/QApplication>
#include <QtWidgets/QPushButton>
#endif
static QSharedPointer<QApplication> pglobal_app;
// api: init
static PyObject* init_wrapper(PyObject* self, PyObject* args)
{
int argc = 1;
char *argv[] = {""};
pglobal_app = QSharedPointer<QApplication>(new QApplication(argc, argv));
Py_RETURN_NONE;
}
// api: launch
static PyObject* launch_wrapper(PyObject* self, PyObject* args)
{
QPushButton button("Exit");
QObject::connect(&button, &QPushButton::clicked, &QApplication::quit);
button.show();
pglobal_app->exec();
Py_RETURN_NONE;
}
// methods table
static PyMethodDef qt_api_methods[] = {
{ "init", init_wrapper, METH_VARARGS, "init qt_api"},
{ "launch", launch_wrapper, METH_VARARGS, "launch qt_api"},
{ NULL, NULL, 0, NULL }
};
// init qt_api module
PyMODINIT_FUNC initqt_api(void)
{
(void) Py_InitModule("qt_api", qt_api_methods);
}
#!/usr/bin/env python
import sys, os
sys.path.append("build/lib.linux-x86_64-2.7")
import qt_api
qt_api.init()
qt_api.launch()
print "BYE"
当我点击“退出”按钮时,程序会打印BYE然后引发分段错误。
我使用GDB来检查发生了什么。以下是输出。
#0 0x00007fd9872ed869 in QWindow::destroy() () from /usr/lib/x86_64-linux-gnu/libQt5Gui.so.5
#1 0x00007fd988b8e1ad in QWidgetPrivate::deleteTLSysExtra() () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#2 0x00007fd988b6278d in QWidgetPrivate::deleteExtra() () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#3 0x00007fd988b68cf8 in QWidgetPrivate::~QWidgetPrivate() () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#4 0x00007fd988b68f39 in QWidgetPrivate::~QWidgetPrivate() () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#5 0x00007fd9894be666 in QObject::~QObject() () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#6 0x00007fd988b71c7a in QWidget::~QWidget() () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#7 0x00007fd988ea5e0e in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#8 0x00007fd988b8d48d in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#9 0x00007fd9894be666 in QObject::~QObject() () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#10 0x00007fd988b71c7a in QWidget::~QWidget() () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#11 0x00007fd988b8c299 in QDesktopWidget::~QDesktopWidget() () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#12 0x00007fd988b38a5c in QApplication::~QApplication() () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#13 0x00007fd988b38e69 in QApplication::~QApplication() () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#14 0x00007fd9898cf77e in destroy (this=0x233d220)
at /home/charles/tools/Qt5.4.0/5.4/gcc_64/include/QtCore/qsharedpointer_impl.h:151
#15 deref (d=0x233d220) at /home/charles/tools/Qt5.4.0/5.4/gcc_64/include/QtCore/qsharedpointer_impl.h:469
#16 deref (this=<optimized out>) at /home/charles/tools/Qt5.4.0/5.4/gcc_64/include/QtCore/qsharedpointer_impl.h:464
#17 QSharedPointer<QApplication>::~QSharedPointer (this=<optimized out>, __in_chrg=<optimized out>)
at /home/charles/tools/Qt5.4.0/5.4/gcc_64/include/QtCore/qsharedpointer_impl.h:305
#18 0x00007fd98ab15259 in __run_exit_handlers (status=0, listp=0x7fd98ae986c8 <__exit_funcs>,
run_list_atexit=run_list_atexit@entry=true) at exit.c:82
#19 0x00007fd98ab152a5 in __GI_exit (status=<optimized out>) at exit.c:104
QApplication::quit()
,我该怎么办?非常感谢你。
答案 0 :(得分:2)
让我们看看你的launch_wrapper
:
// api: launch
static PyObject* launch_wrapper(PyObject* self, PyObject* args)
{
QPushButton button("Exit");
QObject::connect(&button, &QPushButton::clicked, &QApplication::quit);
button.show();
pglobal_app->exec();
Py_RETURN_NONE;
}
在这里创建一个QPushButton
,连接它,显示它,然后输入主要的Qt事件循环。
但是你在堆栈上创建它,所以当你单击该按钮时,主事件循环返回,你的launch_wrapper
返回,并且QPushButton
在出路时被销毁。
现在,您的pglobal_app
是静态的,因此在所有使用过的代码返回后,只有在QPushButton
消失后很长时间内,它才会被销毁。
但内部Qt几乎为所有对象保留了父母和孩子的层次结构,父母拥有孩子。因此,当QApplication被销毁时,它也会摧毁其所有孩子,包括你的QPushButton
。
所以你有一个对象被摧毁了两次。这是一种双重自由和未定义的行为。因此崩溃。
要解决此问题,请在堆上创建所有GUI元素(即QPushButton* button = new QPushButton("Exit");
,然后让Qt使用父/子层次结构清理它。