6. Resource allocation and release
Principle 6.1 define the application and release principles for dynamic product memory
Note: There are a large number of memory problems mainly due to chaotic rules for applying for and releasing memory:
After applying for memory, it is passed into the subroutine and used and released by the subroutine;
The sub-program applies for memory and returns the parent program. after calling the sub-program, the sub-program is released in a function.
General principles for memory application and release:
When an object is out of its scope, it should be immediately released and: who applies for and who releases it.
Memory allocated in the function, which must be released before exiting the function to avoid cross-function release;
The memory of the data member in the class, which is confirmed and released in the Destructor;
Memory space of global variables and static variables is recycled by the operating system when the process exits or when the corresponding shared library is detached;
If many program branches or memory resources are not allocated and released in the same place, use resource tracking management techniques such as raiI.
.
Rule 6.1 clarifies operator new behavior and check Policy
Note: When operator new cannot meet a memory allocation requirement, an exception is thrown by default, and a null pointer can be returned (by compiling and selecting
Item ). The Team clarified operator new operations. After applying for memory, immediately check whether the pointer is null or handle exceptions.
Example: capture exceptions to handle memory application failures
Char * pbuffer = NULL;
Try
{
Pbuffer = new char [buffer_size];
}
Catch (...)
{
Pbuffer = NULL;
Return ef_fail;
}
Or perform non-null judgment:
Char * pbuffer = new char [buffer_size];
If (null = pbuffer)
{
Return er_fail;
}
Rule 6.2 immediately sets the pointer to null after the memory is released to prevent the generation of a wild pointer.
Note: After free or delete is released, the pointer is set to null immediately to prevent "wild pointer ". This kind of judgment is best
Encapsulation. For more information, see Recommendation 6.2.
Example:
Char * pbuffer = new char [buffer_size];
//...
Delete [] pbuffer;
Pbuffer = NULL;
Rule 6.3 Delete is used to release a single object and delete is used to release an array object.
Note: delete is used for deleting a single object, and delete [] is used for deleting an array object. The reason is:
Call the action contained in new: Apply for a piece of memory from the system, if the object calls the corresponding constructor.
Call the action contained in new [N]: Apply to accommodate n objects plus a bit of memory to save the number of elements in the array; call n construction times
The function initializes n objects in the memory.
Call the action contained in Delete: if an object calls the corresponding destructor, the memory is returned to the system.
Call the action contained in Delete []: Obtain N values from new [], call the corresponding destructor n times, and return the memory to the system.
Example:
STD: string * string = new STD: string;
STD: string * stringarray = new STD: String [100];
Delete string;
String = NULL;
Delete [] stringarray;
Stringarray = NULL;
If delete stringarray; is used, 99 of the 100 string objects pointed to by stringarray are not destroyed because
The Destructor is not called at all, and the results are unpredictable. Different compilers have different results.
Rule 6.4 releases the structure (class) pointer, first releases the memory space of its member pointer
Example: The following is a piece of product code with Memory leakage:
Struct store_buf_s
{
Ulong ullen;
Uchar * pcdata;
} Store_buf_t;
Void func ()
{
Store_buf_t * pststoragebuff = NULL;
// Apply for structured memory ....
// Program processing...
Free (pststoragebuff );
Return;
}
Pststoragebuff, pststoragebuff-> pcdata cannot be deleted first. The structure pointer must be deleted from the underlying
Delete in the upper-layer order. That is:
Free (pststoragebuff-> pcdata );
Free (pststoragebuff );
Rule 6.5 first releases the memory of each element pointer in the array when releasing the pointer Array
Note: When releasing the pointer array, make sure that each element pointer in the array has been released, so as not to cause memory leakage.
Example:
Struct dirent ** namelist;
Int n = scandir (path. c_str (), & namelist, 0, alphasort); // [1]
Int I = 0;
For (I; I <n; ++ I)
{
String name = namelist [I]-> d_name;
Free (namelist [I]); // [2]
If (name! = "..." & Name! = ".")
{
//.........
++ Filenum;
If (max_scan_file_num = filenum) // max_scan_file_num = 1000
{
Break;
}
}
}
Free (namelist); // [3]
Return;
From the code above, we can see that the pointer array namelist is allocated by the system function (as shown in [1]), and the memory is released from time to time.
[2] releases a single element of the array and [3] releases the memory of the array.
However, there is a condition in the middle. Only 1000 files are retrieved at a time. If the file in the directory is larger than 1000, the system will not process the subsequent files.
([2] Not executed ). When the number of items in the local directory is small and less than or equal to 1000, no memory leakage occurs.
When the file size exceeds 1000, memory leakage occurs. When releasing a pointer array, note that the memory space of each element is first released.
The correct method is to add the following before [3:
For (Int J = I; j <n; ++ J)
{
Free (namelist [I]);
}
Rule 6.6 does not return partial object pointers
Note: A local object is constructed at a defined point and destroyed immediately at the end of the same scope.
Example:
Char * getparameter ()
{
Cdbconnect dbconnect;
//....................
Return dbconnect. getstring ("paramvalue ");
}
Because the dbconnect object has been destructed and the corresponding pointer has been released, the system coredump will be caused by unauthorized memory access in the future.
Rule 6.7 do not force thread Closure
Note: The thread is forcibly closed, causing internal resource leakage. Use events or semaphores to notify the thread to ensure that the thread calls its own return
Output function. Except when a thread deadlock needs to be forcibly closed.
Example: Force thread closure, causing thread resource leakage.
Cshakehand: cshakehand ()
{
M_hdshakethreadrecv = createthread (null, 0,
(Lpthread_start_routine) threadproc_shakehands,
This, null, & m_ulshakethreadid );
}
Cshakehand ::~ Cshakehand ()
{
Terminatethread (m_hdshakethreadrecv, 0); // force disable
Closehandle (m_hdshakethreadrecv );
}
We recommend that you use the new and delete encapsulation method 6.1 to allocate and release memory.
Note: We recommend that you use the following macros to avoid null pointers and wild pointers to some extent.
# Define hw_new (VAR, classname )\
Do {\
Try \
{\
Var = new classname ;\
}\
Catch (...)\
{\
Var = NULL ;\
}\
Break ;\
} While (0)
// (1) This macro sets VaR to null. Therefore, after calling this macro, you do not need to set VaR to null.
// (2) the hw_delete macro corresponds to new, which is used to release objects allocated by hw_new.
// Note: if an object is allocated as an array (see the description of hw_new), the macro hw_delete_a must be used.
// To release, otherwise it may cause problems. For details, see rule 6.3.
# Define hw_delete (VAR )\
Do \
{\
If (var! = NULL )\
{\
Delete var ;\
Var = NULL ;\
}\
Break ;\
} While (null = var)
// (1) This macro is used to delete an array allocated by hw_new. After deletion, the VaR is set to null.
# Define hw_delete_a (VAR )\
Do \
{\
If (var! = NULL )\
{\
Delete [] var ;\
Var = NULL ;\
}\
Break ;\
} While (null = var)
Directly use the hw_delete and hw_delete_a macros to release the pointer memory space, so that the pointer is not left null.
.
It is recommended that 6.2 avoid allocating and releasing memory in different modules
Note: allocating memory in one module but releasing it in another module will cause a long-distance dependency between the two modules,
Make the program vulnerable.
A module in C ++ is an unclear concept, ranging from a class to a library. If you allocate and release memory between different classes, you must
Consider the initialization and destruction sequence of the two classes. If the memory is allocated and released between different libraries, consider loading or
Uninstall sequence. This long-distance dependency can easily lead to omissions and repeated operations, leading to serious problems.
Sometimes, in the communication mechanism, two entities (such as threads) exchange data or messages. Considering the program execution efficiency, copying is not used.
Instead, the memory is allocated and released at different locations through pointer exchange. In this case, only the number
After the exchange is successful, the other party will be responsible for the release; otherwise, the principle of "who applies and who releases" should be followed. To reduce processing complexity
Can use raiI or smart pointer as appropriate.
Recommendation 6.3 use the raiI feature to help track dynamic allocation
(RaiI is the resource acquisition is initialization) of "resource acquisition is initialization ".
Simple technology that uses Object lifecycles to control program resources (such as memory, file handles, network connections, and mutex volumes.
Generally, raiI Obtains resources during object construction, and then controls resource access so that the resources are within the object's lifecycle.
Always valid. Finally, resources are released during object analysis. This approach has two benefits:
We do not need to release resources explicitly.
The resources required by the object are always valid during its life cycle. In this way, you can simplify the logic,
Improve efficiency.
The smart pointer of the C ++ class library is one of the following:
Auto_ptr is a template class provided by the Standard C ++ library. It uses pointers for initialization and its access method is the same as that provided by pointers. In auto_ptr
When you exit the scope, the specified object can be automatically deleted implicitly. In this way, you can use auto_ptr like a normal pointer instead
Consider release issues. Note: copying auto_ptr will cause modification. The original auto_ptr will not point to any object,
The new auto_ptr takes over the object memory and is responsible for automatic deletion. Therefore, auto_ptr cannot be used again after replication, and const cannot be copied.
Auto_ptr.
The boost Library provides a new type of smart pointer shared_ptr, which solves the problem of sharing object ownership among multiple pointers.
It also meets the requirements of the container on elements, so it can be safely put into the container. Shared_ptr resolves the destruction of the mobile semantics of auto_ptr.
.
For more information about how to use auto_ptr and shared_ptr, see the C ++ standard library.
Example: you do not need to explicitly release mutex resources when using raiI.
Class my_scope_lock
{
Public:
My_scope_lock (locktype & _ Lock): m_lock (_ Lock)
{
M_lock.occupy ();
}
~ My_scope_lock ()
{
M_lock.relase ();
}
Protected:
Locktype m_lock;
}
Bool class data: Update ()
{
My_scope_lock l_lock (m_mutex_lock );
If ()
{
Return false;
}
Else
{
// Execute
}
Return true;
}