The Management QT memory leak

Disclaimer: This article is a blogger original article, shall not be reproduced without the bloggers allowed. https://blog.csdn.net/u014746838/article/details/86702194

I. Introduction
  Qt memory management: Qt inside can maintain a hierarchy of objects. For visual elements, this hierarchy is the relationship with the parent component subassembly; for non-visual elements, it is an object affiliation to another object. In Qt, the Qt, the parent will delete deleted along its children. 
  C ++, delete and new must be paired (one to one): delete less, the memory leak, much bigger trouble. When Qt seldom used in new delete, and because QObject class inherited class, set the parent (addChild setParent function may also be used in the construction or parent) so parent is delete, the parent child are all related automatically delete, without the user manual processing. But the parent is not the child is new to distinguish it out or allocated on the stack. This reflects the strong delete, any object can be freed, and the delete stack objects can lead to memory errors, which need to know Qt semi-automatic memory management. Another problem: child do not know whether they have been delete it out, it may appear wild pointer. They would have to understand the smart pointer QPointer Qt.

Second, Detailed
1, the Qt semi-automatic memory management
(1) and its derived class QObject objects, if the object whose parent non-zero, then the destructor will be its parent destructor.

(2) Object QWidget its derived classes may be provided Qt :: WA_DeleteOnClose flag (will close when the destructor of the object).

(3) Object QAbstractAnimation derived class, may be provided QAbstractAnimation :: DeleteWhenStopped.

(4)QRunnable::setAutoDelete()、MediaSource::setAutoDelete()。

(5) parent-child relationships: parent, child object, parent-child relationship. This is independent of inheritance in Qt unique to the class, the transmission parameters related with parent (base classes, derived classes, or parent class, subclass, which is, independent of the parent for the system is derived).

2, memory problems examples

  • Example 1
#include <QApplication>  
#include <QLabel>  

int main(int argc, char *argv[])  
{  
    QApplication a(argc, argv);  
    QLabel *label = new QLabel("Hello Qt!");  
    label->show();  
    return a.exec();  
} 

Analysis:  label neither the parent, nor its call delete, it will cause a memory leak. This small examples in the book pointer memory problems will appear. Improved way: assignments on the stack instead of the heap, as follows:

(1) assignment on the stack instead of the heap:

#include <QApplication>  
#include <QLabel>  

int main(int argc, char *argv[])  
{  
    QApplication a(argc, argv);  
    QLabel label("Hello Qt!");  
    label.show();  
    return a.exec();  
}  

(2) set the flag, close (after) will delete label:

label->setAttribute(Qt::WA_DeleteOnClose);  

(3) new manually after delete:

#include <QApplication>  
#include <QLabel>  

int main(int argc, char *argv[])  
{  
    int ret = 0;  
    QApplication a(argc, argv);  
    QLabel *label = new QLabel("Hello Qt!");  
    label->show();  
    ret = a.exec();  
    delete label;  
    return ret;  
}  
  • Example 2
#include <QApplication>  
#include <QLabel>  
int main(int argc, char *argv[])  
{  
    QApplication app(argc, argv);  
    QLabel label("Hello Qt!");  
    label.show();  
    label.setAttribute(Qt::WA_DeleteOnClose);  
    return app.exec();  
}

Analysis: The program crashes because when the label is close, delete & label; but the label objects are allocated on the stack memory space, delete the address on the stack to be wrong. Some people label is understood to delete twice by mistake, you can test QLabel label ( "Hello Qt!" ); Label.show (); delete & label; first delete an error occurs.

  • Example 3
#include <QApplication>  
#include <QLabel>  
int main(int argc, char* argv[])  
{  
   QApplication app(argc, argv);  
   QLabel label("Hello Qt!");  
   QWidget w;  
   label.setParent(&w);  
   w.show();  
   return app.exec();  
} 

Analysis: crash when closed w time. Object has an internal list, will save the children, as well as a pointer to save the parent, when their own destruction, will remove themselves from the parent list and destructors all children. w ratio label is first destructor, when w is destructor deletes objects label chilren list, but the label is on the object due to delete the stack on the stack and is assigned to an error.

 Improve the way:

(1) adjust the sequence ensuring its parent label to be destructed when the label destructor remove themselves from their list of the parent object, and w destructor, Children in the list there will be allocated in the stack the objects.

#include <QApplication>  
#include <QLabel>  
int main(int argc, char* argv[])  
{  
   QApplication app(argc, argv);  
   QWidget w;  
   QLabel label("Hello Qt!");  
   label.setParent(&w);  
   w.show();  
   return app.exec();  
}

(2) The label assigned to the heap

QLabel *label = new QLabel("Hello Qt!");
label->setParent(&w)

or:

QLabel *label = new QLabel("Hello Qt!",this);
  • Example 4

Wild pointer

int main(int argc, char* argv[])  
{  
   QApplication app(argc, argv);  
   QWidget *w = new QWidget;  
   QLabel *label = new QLabel("Hello Qt!");  
   label->setParent(w);  
   w->show();  
   delete w;  
   label->setText("go");     //野指针  
   return app.exec();  
}

Analysis: The program ends abnormally, it will delete label when delete w, label become a dangling pointer (label points to the object has been deleted), call label-> setText ( "go") ; error.

Improved way: QPointer smart pointers (QPointer objects can only be used to point and QObject derived classes)

#include <QApplication>  
#include <QLabel>  
#include <QPointer>  
int main(int argc, char* argv[])  
{  
   QApplication app(argc, argv);  
   QWidget *w = new QWidget;  
   QLabel *label = new QLabel("Hello Qt!");  
   label->setParent(w);  
   QPointer<QLabel> p = label;  
   w->show();  
   delete w;  
   if (!p.isNull()) {  
     label->setText("go");  
   }  
   return app.exec();  
}
  • Example 5

deleteLater

  When a QObject is receiving the event queue if she is out to destroy you, that is a problem, so we do not build the QT Delete directly off a QObject, if you must do so, to use the deleteLater QObject () function, it will all events are sent immediately to clean up the complete memory after all deal with, and even call deletelater many times there will not be a problem. 
Send a delete event to event system:

void QObject::deleteLater()  
{  
    QCoreApplication::postEvent(this, new QEvent(QEvent::DeferredDelete));  
} 

Third, memory leak detection tools -VLD
  Visual Leak Detector (the VLD) is free of a memory leak detection tool for the Visual C ++. His features are: You can get a memory leak point of the call stack, if you can, you can also get it in the file and line number; you can get a complete data leak memory; you can set the level of memory leak report; and is open free of charge. But only to support MSVC compiler does not support MingGW compiler. 
Download: http: //vld.codeplex.com/ 
After the installation is complete, copy vld two headers include the installation directory of Qt to the next default include directory, corresponding to the lib directory under the installation directory lib vld copy the file to the default Qt lib directory. Then in main.cpp

#include<vld.h>

Ready to use.

QT smart pointer

(1)QPointer

QPointer is a template class. It is similar to a normal pointer, except that, QPointer monitored object can be dynamically allocated space, and update the object when the delete. 
QPointer reality principle: In the QPointer saved a QObject pointer and a pointer to the pointer (double pointer) to manage global variables, and QObject when destroy (destructor, QWidget through their own destructor, rather than relying on the QObject) will call QObjectPrivate :: clearGuards function to the global GuardHash double pointer that is set to * zero, because the problem is two-pointer, so QPointer pointer to zero the course. With isNull judgment on it is empty.
 

// QPointer 表现类似普通指针   
QDate *mydate = new QDate(QDate::currentDate());   
QPointer mypointer = mydata;   
mydate->year();    // -> 2005   
mypointer->year(); // -> 2005   

// 当对象 delete 之后,QPointer 会有不同的表现   
delete mydate;   

if(mydate == NULL)   
    printf("clean pointer");   
else   
    printf("dangling pointer");   
// 输出 dangling pointer   

if(mypointer.isNull())   
    printf("clean pointer");   
else   
    printf("dangling pointer");  

// 输出 clean pointer

(2) automatic garbage collection mechanism QObjectCleanupHandler: 
Qt objects Cleaner is a very important part to achieve automatic garbage collection. QObjectCleanupHandler can register a lot of sub-objects, and automatically delete all child objects in their own time to delete. At the same time, it can be recognized whether a child object is deleted, so as to remove it from the list of child objects. This class may be used in the cleaning operation is not in the same class hierarchy, for example, when the button is pressed to close many windows need, since the parent attribute window button to another window is not possible, in which case the use of this class will be quite Convenience.
 

#include <QApplication>  
#include <QObjectCleanupHandler>  
#include <QPushButton>  

int main(int argc, char* argv[])  
{  
   QApplication app(argc, argv);  
   // 创建实例  
   QObjectCleanupHandler *cleaner = new QObjectCleanupHandler;  
   // 创建窗口  
   QPushButton *w = new QPushButton("Remove Me");  
   w->show();  
   // 注册第一个按钮  
   cleaner->add(w);  
   // 如果第一个按钮点击之后,删除自身  
   QObject::connect(w, SIGNAL(clicked()), w, SLOT(deleteLater()));  
   // 创建第二个按钮,
注意,这个按钮没有任何动作  
   w = new QPushButton("Nothing");  
   cleaner->add(w);  
   w->show();  
   // 创建第三个按钮,删除所有  
   w = new QPushButton("Remove All");  
   cleaner->add(w);  
   QObject::connect(w, SIGNAL(clicked()), cleaner, SLOT(deleteLater()));  
   w->show();  
   return app.exec();  
}
//在上面的代码中,创建了三个仅有一个按钮的窗口。第一个按钮点击后,会删除掉自己(通过 deleteLater() 槽),此时,cleaner 会自动将其从自己的列表中清除。第三个按钮点击后会删除 cleaner,这样做会同时删除掉所有未关闭的窗口。

 

Guess you like

Origin blog.csdn.net/u014746838/article/details/86702194