This article is first published on my homepage http://www.devbean.info and will be published directly there later. Now we have an article in Flex 4 and a series from C ++ to Objective-C. Thank you for your support!
A strong language always explicitly or implicitly contains the type information of an object when creating an object. That is to say, when a strong language allocates the object memory space, it will always be associated with the object type. In contrast, the weak type language does not. After the memory space is allocated, there are two ways to release the space: manually release, or use the garbage collector. C ++ requires developers to manually release memory space. The advantage of doing so is that developers have full control over the memory and know when to release the memory. Java uses the garbage collector. In the background, a thread constantly checks which objects are not used and can be recycled based on certain algorithms. In this way, developers can be freed from the underlying implementation, and they only need to focus on the business logic.
This article focuses on the memory management of Qt. Here we will use the Qt mechanism to implement a simple garbage collector.
C ++ Memory Management Mechanism
C ++ requires developers to manage their own memory. There are three policies:
The last is usually known as "Memory leakage" and is considered a bug. Therefore, we need to select which of the first two is more appropriate. Sometimes, the object created by delete is much easier than all its sub-objects. Sometimes, it is quite difficult to find the last object.
Qt Memory Management Mechanism
Qt can maintain the object hierarchy internally. For visual elements, this hierarchy is the relationship between child components and parent components. For non-visual elements, it is the subordination between an object and another object. In Qt, deleting a parent object deletes its sub-objects together. This helps reduce memory problems by 90% and forms a mechanism similar to garbage collection.
QPointer
QPointer is a template class. It is similar to a common pointer. The difference is that QPointer can monitor objects that dynamically allocate space and update objects when they are deleted.
- // QPointer is similar to a normal pointer.
- QDate * mydate = new QDate (QDate: currentDate ());
- QPointer mypointer = mydata;
- Mydate-> year (); //-> 2005
- Mypointer-> year (); //-> 2005
- // After the object is deleted, QPointer has different performances.
- Delete mydate;
- If (mydate = NULL)
- Printf ("clean pointer ");
- Else
- Printf ("dangling pointer ");
- // Output dangling pointer
- If (mypointer. isNull ())
- Printf ("clean pointer ");
- Else
- Printf ("dangling pointer ");
- // Output clean pointer
Pay attention to the above Code. After a original pointer is deleted, its value is not set to NULL, so it becomes a wild pointer. However, QPionter does not have this problem.
QObjectCleanupHandler
Qt object cleaner is an important part of automatic garbage collection. It can register many sub-objects and automatically delete all sub-objects when you delete them. At the same time, it can also identify whether a sub-object is deleted from its sub-Object List. This class can be used to clear classes that are not in the same level. For example, when a button is pressed, many windows need to be closed. Because the parent attribute of a window cannot be set to a button of another window, in this case, it is quite convenient to use this class.
- // Create an instance
- QObjectCleanupHandler * cleaner = new QObjectCleanupHandler;
- // Create a window
- QPushButton * w = new QPushButton ("Remove Me ");
- W-> show ();
- // Register the first button
- Cleaner-> add (w );
- // If the first button is clicked, delete itself
- Connect (w, SIGNAL (clicked (), w, SLOT (deleteLater ()));
- // Create the second button. Note that this button does not take any action.
- W = new QPushButton ("Nothing ");
- Cleaner-> add (w );
- W-> show ();
- // Create the third button to delete all
- W = new QPushButton ("Remove All ");
- Cleaner-> add (w );
- Connect (w, SIGNAL (clicked (), cleaner, SLOT (deleteLater ()));
- W-> show ();
In the code above, three windows with only one button are created. When the first button is clicked, it will delete itself through the deleteLater () slot. At this time, cleaner will automatically clear it from its own list. When the third button is clicked, cleaner is deleted. In this way, all unclosed windows are deleted.
Qt garbage collection
As the object becomes more and more complex, it is difficult to decide when to perform the delete operation when this object is used in many places. Fortunately, Qt has a good garbage collection mechanism for all classes inherited from QObject. There are many implementation methods for garbage collection, the simplest is reference counting, and the other is to save all objects. The two implementation methods are described in detail below.
Reference count
Application counting is the simplest implementation of garbage collection: every time an object is created, the counter is added with 1, and every time one is deleted, the number is reduced by 1.
- class CountedObject
- {
- public:
- CountedObject()
- {
- ctr=0;
- }
-
- void attach()
- {
- ctr++;
- }
-
- void detach()
- {
- ctr--;
- if(ctr <= 0)
- delete this;
- }
- private:
- int ctr;
- };
After each sub-object is created, the attach () function should be called to add 1 to the counter. When deleting the sub-object, the detach () function should be called to update the counter. However, this class is very primitive and there is no convenient Qt mechanism. The following is an implementation of the Qt version:
- class CountedObject : public QObject
- {
- Q_OBJECT
- public:
- CountedObject()
- {
- ctr=0;
- }
-
- void attach(QObject *obj)
- {
- ctr++;
- connect(obj, SIGNAL(destroyed(QObject*)), SLOT(detach()));
- }
-
- public slots:
- void detach()
- {
- ctr--;
- if(ctr <= 0)
- delete this;
- }
-
- private:
- int ctr;
- };
We use the Qt signal slot mechanism to automatically reduce the counter value when the object is destroyed. However, our implementation does not prevent two attach () calls during object creation ().
Record Owner
A more appropriate implementation is to remember not only several objects hold references, but also what objects they are. For example:
- Class CountedObject: public QObject
- {
- Public:
- CountedObject ()
- {
- }
- Void attach (QObject * obj)
- {
- // Check the owner
- If (obj = 0)
- Return;
- // Check whether it has been added
- If (owners. contains (obj ))
- Return;
- // Register
- Owners. append (obj );
- Connect (obj, SIGNAL (destroyed (QObject *), SLOT (detach (QObject *)));
- }
- Public slots:
- Void detach (QObject * obj)
- {
- // Delete
- Owners. removeAll (obj );
- // If the last object is deleted, delete itself.
- If (owners. size () = 0)
- Delete this;
- }
- Private:
- QList owners;
- };
Now our implementation can prevent an object from calling attach () and detach () multiple times. However, another problem is that we cannot guarantee that the object will call the attach () function for registration. After all, this is not a built-in mechanism of C ++. One solution is that the implementation of redefinition of the new operator is equally complicated, but it can avoid the case that some objects do not call attach () registration ).
This article comes from DevBean's World: http://www.devbean.info.
When reprinting, indicate the original source of the article: http://www.devbean.info/2011/03/qt_memory_management /.
This article is from the "bean space" blog, please be sure to keep this source http://devbean.blog.51cto.com/448512/526734