`double free or corruption (out)` error on a stack QDialog with the `WA_DeleteOnClose` attribute set - qt

Given the following fragments of code :
class MyDialog : public QDialog
{
...
};
MyDialog::~MyDialog()
{
qInfo() << "~MyDialog()";
}
and
// scope begins
MyDialog d;
d.setAttribute( WA_DeleteOnClose, true );
int result = d.exec();
qInfo() << "After exec";
// scope ends
I get the following output
~MyDialog()
double free or corruption (out)
Aborted (core dumped)
Without d.setAttribute( WA_DeleteOnClose, true ); everything is fine and expected.
NOTE : I know that there is no need to use the delete on close in this case as the dialog deletes when leaving the scope. I also don't need for a "better solution" etc (I've read a lot of posts on SO and Qt Centre Forum with these irrelevant answers). The question is Why the error occurs at the first time the ~QDialog() is called ? And maybe Am I right that the error occurs at the first time the ~QDialog() is called?

I've got the answer in the Qt Forum : link.
The source code for the QDialog class contains the following lines:
//QDialog::exec()
if (deleteOnClose)
delete this;
return res;
which is, ofc, causes a crash if this points to a stack object.

Try this instead:
MyDialog* d = new MyDialog;
d->setAttribute( WA_DeleteOnClose, true );
int result = d->exec();
Either new QobjectDerived or new QobjectDerived(this) for dynamic allocation and then the dynamic deallocation could finalize the object destruction just once. That attribute WA_DeleteOnClose set is obviously provoking internal delete when the dialog getting closed but no second destructor call as in case with that object allocated on stack.

You're creating an object on the stack and then try to delete it with delete (indirectly via the WA_DeleteOnClose - flag). I don't see why you would not get a double delete then.

Related

Qt - start process with click event and stop it again with the second click event

I found time to investigate a bit into QT, and it is very interesting for me. However, right now I am encountering a problem that I am not aware about how to solve it. My aim is actually simple. I have a QCheckBox that I want to activate. If it is activated, I am starting a process (I am opening a file, reading it, taking some values out and change different labels accordingly). This process is repeated until the user is deactivating the QCheckBox. Some small code example to get a better idea of what I am going to do.
void Analyzer::on_actualTemperature_stateChanged(int arg1)
{
// Read data and change labels
if (arg1 != 0)
{
qDebug() << "Start data analysis";
// Infinity loop to get the data and display it
while true
{
// Open file and extract data
const actualTemperature = getData();
// Change any label or do something with the data
ui->anyLabel->setText(actualTemperature);
// Some break
QThread::sleep(1);
// Leave the loop if user deactivate the QCheckBox
// Something like on_actualTemperature_stateChange == 0
}
}
// Stop reading the data
else
{
qDebug() << "Stop data analysis";
}
}
It is obvious that after activating the QCheckBox, the loop will not finish at all and the GUI will not recognize anything anymore. Hence, I guess I have to start some new thread and have to kill it. However, I have no idea how to proceed here. An idea would be:
void Analyzer::on_actualTemperature_stateChanged(int arg1)
{
// Read data and change labels
if (arg1 != 0)
{
// Start reading the file and updating the label using some other thread
startThread(XY);
}
// Stop reading the data
else
{
// Kill thread 1234
killThread(XY);
}
}
Any hint is warmly welcomed and I hope this question is not too basic for you. Thank you for reading, Tobi.
I think killing a running thread is not a decent behavior. Let's be gentle to our threads with a loop control variable. In this example it named keepLoop. Set keepLoop when checkbox checked. Then start thread if it is not running. We are using QtConcurrent::run, and monitoring it by a QFuture in this case.
connect(ui->checkBox, &QCheckBox::toggled,
[&](const bool checked) {
analyzer->keepLoop = checked;
if (checked && !future.isRunning())
future = QtConcurrent::run(analyzer, &Analyzer::on_actualTemperature_stateChanged);
}
);
Don't call user interface slots directly, instead connect them to signals. Connections will be queued connection when signals emitted from another thread. It means slots will be called in event loop of main thread and changes will be shown when the next frame painted.
connect(analyzer, &Analyzer::temperatureCalculated, ui->anyLabel, &QLabel::setText);
Our asynchronous function does not forced to die immediately when user toggle checkbox. Instead we letting it to finish the iteration it already on halfway through.
Analyzer::on_actualTemperature_stateChanged() {
while (keepLoop) {
// Open file and extract data
const QString& actualTemperature = getData();
// send data
emit temperatureCalculated(actualTemperature);
}
}
You can use atomic bool if you want a more precise loop control.
Bonus:
If you don't want to mess with threads, you can avoid GUI freezing by using QTimer to run your loop periodically in main thread.

How can I check if QPdfWriter object can write to the specified file?

I am creating the PDF documents in Qt using command:
QPdfWriter *pdf;
pdf = new QPdfWriter(filename);
Sometimes the object is not created due to a wrong filename or document exists and is open in other application...
How can I check if object was created (if the pdf pointer points to the valid object)?
EDIT: My mistake was, that object is not created. It is not true. The QPdfWriter object is created, but there is no exception or error generated.
I can set some properties.
The problem will occur later when I am trying to write something to the document - see comments of the last 3 commands:
pdf->setParent(this);
pdf->setPageSize(QPdfWriter::A4);
pdf->setPageOrientation(QPageLayout::Orientation::Landscape);
QPainter *p = new QPainter(pdf); //got message: QPainter::begin(): Returned false
ui->chartView->render(p); // no error
p->end(); // got message: QPainter::end: Painter not active, aborted
I read the documentation of QpdfWriter and parent classes QPagedPaintDevice and QPaintDevice. I cannot find any property/method to check if I can write to the document...
So question - how to check if I can write to the document?
Ive just stumpled over the same issue, the hint with bool QFileInfo::isWritable() const didn't do the trick for me. Though you basically gave the answer yourself with the comment on the third last command, with the return value of QPainter::begin() you can check if the QPdfWriter can generate the pdf.
QPainter *p = new QPainter;
if (p->begin(pdf)) {
ui->chartView->render(p);
p->end();
} else {
// error message...
}

Should accept() be used only at the end of a slot?

I see the accept() somewhat similar to a return, so I've been putting it a the end of my slots with no code afterwards. That is, the accept() "finishes" the execution of the dialog.
Nevertheless, I came across the need to close a dialog and open a new one from a slot in the first one. Therefore, what I thought was moving the accept() to the beginning of the slot and initializing the second dialog after it. Something like the following:
void FirstDialog:slotFirstDialog()
{
accept();
// Setup second dialog arguments
// ...
SecondDialog *sd = new SecondDialog();
sd->exec();
}
Is this use of accept() valid? Is it good practice?
I'd avoid it. Calling accept() can trigger a delayed deletion of FirstDialog (say, if it has the Qt::WA_DeleteOnClose flag set)1; in that case, it would be deleted in one of the first events dispatched by the nested event loop (sd->exec()), which would lead to go on executing code in a method of an instance that has been deleted. This is just a sample problem on the top of my head, I'm sure others can be found.
I'd probably just hide the dialog before calling exec() on the other, and call accept() after the end of the nested event loop.
void FirstDialog:slotFirstDialog()
{
// Setup second dialog arguments
// ...
SecondDialog *sd = new SecondDialog();
hide();
sd->exec();
accept();
// NB are we leaking sd?
}
By the way:
SecondDialog *sd = new SecondDialog();
sd->exec();
here you are allocating on the heap a dialog without a parent, so either you set the Qt::WA_DeleteOnClose or explicitly call this->deleteLater() inside its code, or you are leaking the dialog instance.
Notes:
and it is explicitly remarked in the documentation
As with QWidget::close(), done() deletes the dialog if the Qt::WA_DeleteOnClose flag is set.
QDialog::accept calls QDialog::done with a dialog code Accepted. Here is how QDialog::done looks like:
void QDialog::done(int r)
{
Q_D(QDialog);
setResult(r);
hide();
d->close_helper(QWidgetPrivate::CloseNoEvent);
d->resetModalitySetByOpen();
emit finished(r);
if (r == Accepted)
emit accepted();
else if (r == Rejected)
emit rejected();
}
which, according to the documentation:
Hides the modal dialog and sets the result code to Accepted.
With this in mind, I think this is not a question of a good practice, but of what your application logic requires.

OpenCV and (not) returning IplImages, when is it okay, when not?

is it okay to do something like this, the code snippet is of course not complete, just to show what I mean:
void draw(IplImage* image){
cvLine(image,cvPoint(20,20),cvPoint(100,100),cvScalar(0,0,255),1);}
int main(){
cvNamedWindow("preview",CV_WINDOW_AUTOSIZE);
IplImage* image;
image=cvCreateImage(cvSize(480,360),8,3);
while(true){
draw(image);
cvShowImage("preview",image);
int ops=cvWaitKey(10)
if ops!=-1 break;}
cvReleaseImage(&image);cvDestroyWindow("preview");return 0;
}
or will it cause problems if I don't return the IplImage like this:
IplImage* draw(IplImage* image){
cvLine(image,cvPoint(20,20),cvPoint(100,100),cvScalar(0,0,255),1);return image;}
well, the reason why I'm asking is that sometimes it works if I don't return the IplImage. However it may also happen that I'll receive some sort of NULL pointer error message in other cases. If for example I release the image in the function and then create it anew right after that, still being in that function, a crash may happen.
You don't need to return anything, but you definitely need to check for failures!
The problem is that you are not coding safely. You are never checking for failures when calling OpenCV functions, which may result in draw() receiving a NULL pointer as parameter, and that might cause a crash or some other weird behavior along the way.
The first thing you should do is start coding defensively:
IplImage* image = cvCreateImage(cvSize(480,360),8,3);
if (!image)
{
// print error and quit
}
and it wouldn't hurt to add a safety check inside your function:
void draw(IplImage* image)
{
if (!image)
{
// print error
return;
}
cvLine(image,cvPoint(20,20),cvPoint(100,100),cvScalar(0,0,255),1);
}

Qt Modeless Dialog Destruction

From what I understand to make dialog Modeless you have to allocate it on the heap. By Doing something like this:
MyDialog* dlg = new MyDialog(this);
dlg->show();
dlg->raise();
Since exec() ignores Modal Property. However now there is a memory leak since nothing deallocates memory pointed to by dlg pointer until the application is closed. I found one solution here http://tinf2.vub.ac.be/~dvermeir/manuals/KDE20Development-html/ch08lev1sec3.html#ch08list09 at the end of the page and was wondering whether there was a less cumbersome way having Modeless dialog.
You can use the attribute Qt::WA_DeleteOnClose to destroy the window when it is closed/hidden, and QWeakPointer (or QPointer) with a static variable to track the existence of the window inside the slot/function which opens it:
void MyWindow::openDialog() {
static QWeakPointer<MyDialog> dlg_;
if (!dlg_)
dlg_ = new MyDialog(this);
MyDialog *dlg = dlg_.data();
dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->show();
dlg->raise();
dlg->activateWindow();
}
I'd schedule it for deletion at the time it's work is finished by using deleteLater:
void MyDialog::MyDialog(QWidget *parent) {
// ...
connect(this, SIGNAL(finished(int)), SLOT(deleteLater)));
}
This approach will preclude you from examining it after the finished signal has been emitted (unless you can guarantee that any accesses happen before everything gets back to the event loop when the deletion is actually performed).
Personally, I would choose between either using
dlg->setAttribute(Qt::WA_DeleteOnClose);
or making the dialog a -dynamically allocated- member i.e. creating it only once:
// constructor
: dialog_(0)
// member function
{
if (! dialog_)
dialog_ = new MyDialog(this);
dialog_->show();
dialog_->raise();
}
This way the dialog is deleted when the parent dies, and only needs to be constructed once.

Resources