QMdiSubwindow deleted twice in singleton destructor
-
Hi
I have a singleton class that has a QMdiArea. If I add a new subwindow to it, QMdiArea wants to delete it twice. I have a minimal example here: (I'm calling SharedWindow::instance() at least once).
// shared_window.h #ifndef SHARED_WINDOW_H #define SHARED_WINDOW_H #include <QObject> #include <QMdiArea> #include <QMdiSubWindow> #include <QMainWindow> class Q_DECL_EXPORT SharedWindow : public QMainWindow { Q_OBJECT public: ~SharedWindow(); // Singleton SharedWindow(SharedWindow const&) = delete; void operator=(SharedWindow const&) = delete; static SharedWindow &instance(void); private: QMdiArea *mdi; // Singleton SharedWindow(); }; #endif // SHARED_WINDOW_H // shared_window.cpp #include "shared_window.h" SharedWindow::SharedWindow() { this->mdi = new QMdiArea(); this->setCentralWidget(this->mdi); this->mdi->addSubWindow(new QSlider()); this->show(); } SharedWindow::~SharedWindow() { } SharedWindow &SharedWindow::instance() { static SharedWindow i; return i; } Stack trace: 1 ?? 0x7ffff7285cf2 2 ?? 0x7ffff72886f1 3 QMdiSubWindow::~QMdiSubWindow() 0x7ffff728cd5d 4 QMdiSubWindow::~QMdiSubWindow() 0x7ffff728cd99 5 QObjectPrivate::deleteChildren() 0x7ffff61dcb11 6 QWidget::~QWidget() 0x7ffff7154d98 7 QWidget::~QWidget() 0x7ffff7155019 8 QObjectPrivate::deleteChildren() 0x7ffff61dcb11 9 QWidget::~QWidget() 0x7ffff7154d98 10 QMdiArea::~QMdiArea() 0x7ffff7278a39 11 QObjectPrivate::deleteChildren() 0x7ffff61dcb11 12 QWidget::~QWidget() 0x7ffff7154d98 13 SharedWindow::~SharedWindow shared_window.cpp 19 0x7fffe37adffc 14 __run_exit_handlers 0x7ffff4e8fbe8 15 exit 0x7ffff4e8fc35 16 __libc_start_main 0x7ffff4e7a748 17 _start 0x400e49
Any ideas?
-
Hi and welcome to devnet,
Because it will be deleted by its parent when its parent gets destroyed (see Object Trees & Ownership)
You should also avoid static QWidget object. They might get created before your QApplication object which should be the first thing created before using any GUI features.
Out of curiosity, why are you using a singleton to create a QMainWindow ?
-
Hi
Yes, that's what I was thinking too, but why is it deleted twice then? My QMainWindow is the parent of the QMdiArea, which is the parent of the QMdiSubWindow. And my QMainWindow doesn't have a parent. I'm also never deleting something manually. So why is it segfaulting anyway?
Would it be better if the QMainWindow was a dynamically allocated member of SharedWindow instead of it's base then?
I try to create a window that is shared by multiple plugins. They should later be able to (dynamically) push widgets to it. The window itself will also be a plugin, so I can't handle that when the plugins are loaded. A singleton seemed to be the easiest way to have one "global' object.
-
Since I don't know the rest of your code, I can't comment on that part.
Technically, it should be the other way around, your application loads the plugins and pulls widgets from them. That will also avoid making a tight coupling between the plugins and your MainWindow class.
-
I got it working! You were right, after some more testing, it turned out, that my class was deleted after QApplication was already deleted. That's what I'm using now:
// shared_window.h #ifndef SHARED_WINDOW_H #define SHARED_WINDOW_H #include <QObject> #include <QMdiArea> #include <QMdiSubWindow> #include <QMainWindow> class ROBOTCORE_EXPORT SharedWindow : public QObject { Q_OBJECT // Singleton Q_DISABLE_COPY(SharedWindow) public: ~SharedWindow(); static SharedWindow *instance(void); private: QMdiArea *mdi; static SharedWindow *inst; QMainWindow *wnd; // Singleton SharedWindow(); private slots: void cleanup(void); }; #endif // SHARED_WINDOW_H // shared_window.cpp #include "shared_window.h" SharedWindow *SharedWindow::inst = nullptr; SharedWindow::SharedWindow() { this->wnd = new QMainWindow(); this->mdi = new QMdiArea(); this->wnd->setCentralWidget(this->mdi); this->mdi->addSubWindow(new QSlider()); this->wnd->show(); } void SharedWindow::cleanup() { delete this->wnd; } SharedWindow::~SharedWindow() { } SharedWindow *SharedWindow::instance() { if(SharedWindow::inst == nullptr) { SharedWindow::inst = new SharedWindow(); // Setting qApp as the parent won't do it, don't know why connect(QApplication::instance(), &QApplication::aboutToQuit, SharedWindow::inst, &SharedWindow::cleanup); } return SharedWindow::inst; }
I couldn't delete it from the main application, because I have no control over the main application. Also, my shared window is only used by some specific plugins and isn't part of the main project. The main application has a window of it's own.
Thanks!