0

I have problem in ensuring the dialog is closed/released with the following Qt codes.

 //Segment 1: To open a 'wait' dialog for some long-running tasks
 void MainWindow::ui_showProgressDialog(QString title) {
     dlgProgress = new QProgressDialog(title, tr("Cancel"), 0, 0, this);
     dlgProgress->setAttribute(Qt::WA_DeleteOnClose); // line 1
     dlgProgress->setModal(true);
     dlgProgress->show();
     connect(voidWatcher, SIGNAL(finished()),
             this, SLOT(onPopulationFile()));
 }

 //Segment 2: Attempts to close the 'wait' dialog
 void MainWindow::onPopulationFile() {
    qDebug((dlgProgress == NULL) ? "true" : "false");
    if (dlgProgress) // 
    {
        qDebug("0");
        dlgProgress->close(); // line 2
        qDebug("1");
    }
    qDebug((dlgProgress == NULL) ? "true" : "false");
 }

Issue: When I trigger the call 'ui_showProgressDialog' twice, the second call always crash my program. Originally, my code has no line 1 of segment 1, and from the QtCreator, it always crashes on line 2 of segment 2. Debug message shows as follow

// first call to onPopulationFile
false
0
1
false
// second call to onPopulationFile
false
0
*** CRASH ***    

I read the documentation that NEVER delete objects from different threads, I'm doubt that the call 'onPopulationFile' is invoked from a non-main thread. So I added the line 1 to segment to let the program decide when the delete the object. But it seems not work. Any suggestion to the problem?

Experiment done: If I replace QProgressDialog with QDialog, the program goes without crashes, and the debug message show

// first call to onPopulationFile
false
0
1
false
// second call to onPopulationFile
false
0
1
false

So,

  • Why the second null test in segment 2 always fail? [Edit: I have to explicitly set the variable to NULL]
  • Is there any better way to close the 'wait' dialog?
  • I try to close/release the dialog as I want release memory as soon as possible. Do I really need to manually delete the dialog?

Platform: Qt Opensource 4.8 (x64), Windows 7 (x64), MinGW (rubenvb 4.7.2)

YamHon.CHAN
  • 866
  • 4
  • 20
  • 36

1 Answers1

4

dlgProgress->setAttribute(Qt::WA_DeleteOnClose); deletes the widget when it is closed. As you are calling dlgProgress->close();, after this line the object it points to has been freed, and dlgProgress is now a invalid pointer.

You need to set dlgProgress to null after any call to close, or event better, use the signal Qobject::destroyed().

EDIT:

Qt::WA_DeleteOnClose specify that the object will be deleted if a close event happens. Not exactly how much time it will take. For instance if they are using QObject::deleteLater(), then the object is not deleted right away. Even if it is not the case , pieces of code like

 A* a = new A;
 a->dosomething();
 delete a;
 a->dosomething();

are undefined behavior. The second call to a->dosomething(); may crash (if you are lucky) or may not crash.

UmNyobe
  • 22,539
  • 9
  • 61
  • 90
  • thanks for your comment, but 1) the statement qDebug("1") does not use anything from dlgProgress why it cannot show up in debug msg? 2) connect the signal destroyed() to where? – YamHon.CHAN Jan 31 '13 at 12:47
  • 1
    I am not talking about debug. I am talking about the source of the crash when you call the method the second time... – UmNyobe Jan 31 '13 at 12:56
  • the first "false" of 2nd call to onPopulationFile shows the 'dlgProgress' is not null when entering the onPopoulationFile in the 2nd call. My question is why QDialog work but QProgressDialog fail! – YamHon.CHAN Jan 31 '13 at 13:22
  • Thanks for your information. I edited my program and now it seems going smoothly. – YamHon.CHAN Jan 31 '13 at 15:01