PDA

View Full Version : [solved] Any idea to prevent that crash?



Wurgl
12th January 2011, 23:22
I have here a cut-down example of a crash indirect caused by setAttribute(Qt::WA_DeleteOnClose) and I do not know a nice way to prevent it.

To reproduce:
Compile that snipplet and start it. Then click into the window which shows up (it contains a pushbutton) and after that close the window (where you clicked into) by clicking on the bix X in the title line.

The crash happens because that attribute "Qt::WA_DeleteOnClose" calls the destructor of the main window. Since the small dialog has a parent, it is deleted too. Now it has its own exec() call where it loops.

Now I do not want to drop that "Qt::WA_DeleteOnClose" line, because this would mean unused memory which is still allocated and the application grows and grows ...

I also would like to show the child dialog centered above the main window and since I am lazy, is simple use the parent widget as a parameter during start.

I also would like to avoid a modal dialog.

If I could drop one of these three requirements, the crash would go.

One way could be to clear the parent of the child window. This would mean a lot of coding, since I need to know which child windows exists (there could be many, not just one), but as i wrote: I am lazy ...

Another way could be to drop the exec() call in the opened dialog, which would mean rearranging the logic in the caller, again this needs to handle a collection of a opened subdialogs ... I don't like that, since I am lazy.

Does anyone have another idea?


#include <Qt/qapplication.h>
#include <Qt/qpushbutton.h>
#include <Qt/qmainwindow.h>
#include <Qt/qdialog.h>
#include <Qt/qlabel.h>
#include <Qt/qlayout.h>
#include <Qt/qevent.h>

class SomeMainWin : public QMainWindow {
Q_OBJECT;
public:
SomeMainWin();
virtual ~SomeMainWin();
virtual void closeEvent(QCloseEvent *event);
QPushButton *_openDialog;

public slots:
void openAnDialog();
};

class SomeDialog : public QDialog {
public:
SomeDialog(QWidget *parent);
virtual ~SomeDialog();
int run();
};

int main(int argc, char **argv)
{
QApplication app(argc, argv);
SomeMainWin *myMainWin = new SomeMainWin();
myMainWin->show();
app.exec();
exit(0);
}

SomeMainWin::SomeMainWin()
{
setAttribute(Qt::WA_DeleteOnClose);
_openDialog = new QPushButton("Open");
connect(_openDialog, SIGNAL(clicked()), this, SLOT(openAnDialog()));
setCentralWidget(_openDialog);
}

SomeMainWin::~SomeMainWin()
{
}

void SomeMainWin::closeEvent(QCloseEvent *event)
{
event->accept();
}

void SomeMainWin::openAnDialog()
{
SomeDialog SomeDialog(this);
if(SomeDialog.run() == QDialog::Accepted) {
// ... do this an that
}
}

SomeDialog::SomeDialog(QWidget *parent)
: QDialog(parent)
{
QVBoxLayout *layout = new QVBoxLayout();
setLayout(layout);

QLabel *label = new QLabel("Hello");
layout->addWidget(label);
}

SomeDialog::~SomeDialog()
{
}

int SomeDialog::run()
{
show();
exec();
}

#include "main.moc"


the crash looks like this (it is Suse Linux)

$ ./a.out
QObject: Do not delete object, 'unnamed', during its event handler!
*** glibc detected *** ./a.out: double free or corruption (out): 0x00007fffc1a87630 ***

marcvanriet
12th January 2011, 23:43
Hi,

in the closeEvent() of the dialog, you could do this.deleteLater()

Regards,
Marc

Wurgl
13th January 2011, 00:23
You mean this way?


SomeMainWin::SomeMainWin()
{
// setAttribute(Qt::WA_DeleteOnClose);
_openDialog = new QPushButton("Open");
connect(_openDialog, SIGNAL(clicked()), this, SLOT(openAnDialog()));
setCentralWidget(_openDialog);
}

void SomeMainWin::closeEvent(QCloseEvent *event)
{
event->accept();
deleteLater();
}


Sadly it does not help, still the same crash.

Added after 34 minutes:

But this way it works.


void SomeMainWin::closeEvent(QCloseEvent *event)
{
SomeDialog *dialog;
while((dialog = findChild<SomeDialog *>()) != 0) {
dialog->setParent(0);
dialog->close();
}
event->accept();
}