The so-called resource is that once it is used, it must be returned to the system in the future. The most commonly used resource in C ++ is the dynamic allocation of memory (if the memory is allocated but not released, it will lead to memory leakage), but the memory is only one of the many resources that must be managed. Other common resources include file descriptors, mutex locks, fonts and brushes in the graphic interface, database connections, and network sockets. Regardless of the resource, it is important to return it to the system when it is no longer used.
Suppose we use a library to simulate Investment behaviors (such as stocks and bonds), and various Investment types inherit from one root class Investment:
Class Investment {... // root class in the "Investment type" inheritance system };
Further, we assume that this library supplies a specific investor object through a factory function:
Investment * createInvestment (); // returns a pointer to the dynamically allocated object in the Investment inheritance system. The caller is responsible for deleting it.
// For simplicity, do not write Parameters
To ensure that the resources returned by createInvestment are always released, put the resources into the object, we can rely on C ++'s "automatic destructor call mechanism" to ensure that the resources are released.
Many resources are dynamically allocated in the heap and then used in a single block or function. They should be released when the control flow leaves that block or function. The following example shows how to use auto_ptr to avoid potential resource leakage of f functions:
<Investment> pInv (createInvestment ();... // use pInv as always
// Automatically delete pInv through the destructor of auto_ptr}
This simple example demonstrates two key ideas of "Object-based resource management:
1. The resources returned by createInvestment in the above Code are treated as the initial values of the Manager auto_ptr. In fact, the concept of "Object-based Resource management" Is often referred to as "Resource Acquisition Is Initialization; RAII ), because we almost always initialize a management object in the same statement after obtaining a resource.
Management Objects use destructor to ensure resources are released. No matter how the control flow leaves the block, once the object is destroyed (for example, when the object leaves the scope), its destructor is automatically called and the resource is released.
Note: Because auto_ptr is automatically deleted when it is destroyed, be sure not to let multiple auto_ptr point to the same object at the same time. Otherwise, if the object is deleted more than once, the "undefined behavior" error will occur. To prevent this problem,
Std: auto_ptr <Investment> pInv1 (CreateInvestment (); // point pInv1 to the object returned by CreateInvestment
Std: auto_ptr <investment> pInv2 (pInv1); // now pInv2 points to the object, and pInv1 is set to null
PInv1 = pInv2; // now pInv1 points to the object, and pInv2 is set to null
The alternative to auto_ptr is reference-counting smart pointer; RCSP ). RCSP is also a smart pointer. It keeps track of the total number of objects pointing to a resource and automatically deletes the resource when no one points to it. The behavior type garbage collection provided by RCSP, the difference is that RCSP cannot break the cycle reference (cycles of reference, for example, two objects that are not actually used are mutually referred to by each other, so it seems to be in the "used" status ).
TR1: shared_ptr of tr1 (see cla54) is an RCSP, so you can write f as follows:
Void Func (){... std: tr1: shared_ptr <Investment> pInv1 (createInvestment (); // pInv1 points to crateInvestment. The returned thing is std: tr1: shared_ptr <Investment> pInv2 (pInv1 ); // pInv1 and pInv2 point to the same object pInv1 = pInv2; // same as above, no change ...} // After the function is completed, pInv1 and pInv2 are destroyed, and the objects they refer to are also automatically destroyed.
Because auto_ptr is not perfect, it is indeed very convenient, but there are also defects, you should pay attention to avoid when using it. First, do not use the auto_ptr object as an element of the STL container. The C ++ standard explicitly prohibits such operations, otherwise unexpected results may occur.
Both auto_ptr and tr1: shared_ptr perform the delete rather than delete [] action in their destructor. Therefore, auto_ptr or tr1: shared_ptr cannot be used for dynamically allocated arrays. For example:
Std: auto_ptr <std: string> aps (new std: string [10]); // error! The error delete format is used.
Std: tr1: shared_ptr <int> spi (new int [1024]); // error! The error delete format is used.
Trl1: shared_ptr is usually a better choice because of its intuitive copy behavior. If auto_ptr is selected, the copy Action directs the Copied object to null. Trl1: shared_ptr in the header file <memory>
Then we collected several precautions for auto_ptr:
1. auto_ptr cannot share ownership.
2. auto_ptr cannot point to an array
3. auto_ptr cannot be a container member.
4. auto_ptr cannot be initialized through the value assignment operation.
Std: auto_ptr <int> p (new int (42); // OK
Std: auto_ptr <int> p = new int (42); // ERROR
This is because the auto_ptr constructor is defined as explicit.
5. Do not put auto_ptr into the container
Then I recommend shared_ptr of boost, and read the introduction and examples of shared_ptr on smart pointers.
Five pointer types for auto_ptr deficiency are as follows: For more information, see the relevant documentation and test the new code.
Scoped_ptr |
<Boost/scoped_ptr.hpp> |
Unique ownership of a simple single object. Cannot be copied. |
Scoped_array |
<Boost/scoped_array.hpp> |
Unique ownership of a simple array. Cannot be copied. |
Shared_ptr |
<Boost/shared_ptr.hpp> |
Object ownership shared among multiple pointers. |
Shared_array |
<Boost/shared_array.hpp> |
Array ownership shared among multiple pointers. |
Weak_ptr |
<Boost/weak_ptr.hpp> |
AShared_ptrThe unowned observer of the object. |
Intrusive_ptr |
<Boost/intrusive_ptr.hpp> |
Share Ownership of objects with an intrusive reference count. |
1. shared_ptr is a smart pointer implementation provided by the Boost library. shared_ptr aims to solve the limitations of auto_ptr on object ownership (auto_ptr is exclusive ), the reference counting mechanism provides smart pointers that can share ownership.
2. shared_ptr is safer than auto_ptr
3. shared_ptr can be copied and assigned values, and the copy behavior is equivalent and can be compared. This means that it can be put into the general container (vector, list) of the standard library) and associated container (map ).