Chapter 3rd Resource Management
Resource Management
The so-called resource is that once it is used, it will have to be returned to the system. The most common resource used in C + + programs is dynamic memory allocation (which can lead to memory leaks if the allocated memory is never added back). Other popular resources are file descriptors (files descriptors), mutexes (mutex locks), fonts and brushes in the graphical interface, database connections, and network sockets. No matter what kind of resource, it is important that it be returned to the system when it is no longer used.
Article 13: Managing Resources with objects
Use objects to manage resources.
Suppose a library is used to mold investment behavior, where a variety of investment types are inherited from a root class investment:
Class Investment {...}; Root class in the "Investment type" inheritance system
It is further assumed that this library supplies a investment object of a feature through a factory function:
investment* createinvestment (); Returns a pointer to a dynamically allocated object
Createinvestment the caller uses the object returned by the function, it is the responsibility to delete it. Now consider an F function that fulfills this responsibility:
void F () {
investment* PINV = Createinvestment (); Call the Factory function
...
Delete Pinv; Releases the object that PINV refers to
};
This may seem appropriate, but in some cases F might not be able to delete its own Createinvestment investment object:
It may be a premature return statement in the "..." area. If such a return is executed, the control flow will never touch the DELETE statement.
A similar situation occurs when the use of createinvestment and the delete action is within a loop, and the loop exits prematurely due to a continue or goto statement.
The last possible statement in the "..." area throws an exception, and if so the control flow will not touch the delete.
No matter how the delete is skipped, the leak is not just the memory that contains the investment object, but also any resources that are saved by the investment object.
Careful programming can prevent this type of error, but the code may gradually change back in time. Once the software begins to undergo maintenance, some people may add a return statement or a continue statement without fully understanding its consequences for the function's resource management strategy. What's worse is F's "..." It is possible for a region to invoke a function that "has never thrown an exception in the past and has started doing so after being ' improved '." It is not feasible to rely solely on "F always executes its DELETE statement".
To ensure that the resource returned by Createinvestment is always freed, the resource needs to be placed inside the object, and when the control flow leaves F, the object's destructor will automatically release those resources. In fact, this is the idea of hiding behind these terms: put resources in the object, you can rely on C + + " The destructor automatic invocation mechanism ensures that resources are freed.
Many resources are allocated dynamically within the heap and then used within a single chunk or function. They should be freed when the control flow leaves that block or function. The auto_ptr provided by the standard library is precisely the trait product designed for this situation. Auto_ptr is a "Class pointer object", which is called " Smart pointer, whose destructor automatically calls delete on the object it refers to. The following example how to use auto_ptr to avoid potential resource leakage possibilities of the F function:
void F () {
Std::auto_ptr<investment> PINV (Createinvestment ());
Call the factory function and, as always, use PINV to automatically delete the PINV by Auto_ptr's destructor function
...
}
This simple example demonstrates the two key ideas for "Managing Resources with Objects":
1. Once the resource has been acquired, it is immediately placed within the management object. The resources returned by createinvestment in the above code are treated as the initial value of their manager auto_ptr. In fact, the idea of "managing resources with objects" is often referred to as "the opportunity for resource acquisition is the time of initialization" (Resource Acquisition is initialization; RAII). Because it almost always takes a resource to initialize a management object within the same statement. Sometimes the acquired resources are assigned (rather than initialized) to a management object. But either way, each resource is immediately placed in the management object while it is acquired.
2. Management objects use destructors to ensure that resources are freed. Regardless of how the control flow immediately blocks, once the object is destroyed (for example, when the object is immediately scoped) its destructor is automatically called, and the resource is freed.
Because auto_ptr automatically deletes the object it refers to when it is destroyed, it is important to note that multiple auto_ptr cannot point to the same object at the same time. If that is the case, the object will be deleted more than once, and that will cause the program to appear "Undefined behavior". In order to prevent this problem, auto_ Ptrs has an unusual nature: if you copy them through the copy constructor or the copy assignment operator, they become null, and the copied pointers take the unique ownership of the resource.
Std::auto_ptr<investment> pInv1 (Createinvestment ()); PINV1 point to Createinvestment return object
Std::auto_ptr<investment> pInv2 (PINV1); Now pInv2 points to the object, PINV1 is set to null
PINV1 = PInv2; Now PINV1 points to the object, PINV2 is set to null
This bizarre replication behavior, combined with its underlying condition: "Resources managed by Auto_ptrs must have absolutely no more than one auto_ptr pointing at it at the same time," meaning auto_ptrs is not an excellent way to manage dynamic resource allocation. For example, an STL container requires its elements to play "normal" Replication behavior, so these containers cannot use auto_ptr.
The alternative to auto_ptr is the "Reference Counting Wisdom Pointer" (reference-counting smart pointing; RCSP). The so-called RCSP is also a smart pointer that keeps track of how many objects point to a resource and automatically delete the resource when no one points to it. The behavior provided by RCSP is similar to garbage collection (garbage collection), unlike RCSP's inability to break ring references (cycles of reference, for example, two objects that have not been used to refer to each other, and thus seem to be in "used" state).
TR1 's tr1::shared_ptr (see clause 54) is a RCSP, so you can write F:
void F () {
...
Std::tr1::shared_ptr<investment> PINV (Createinvestment ());
Call the factory function and use PINV to automatically delete the PINV through the shared_ptr destructor
}
This code looks almost identical to the one that uses auto_ptr, but the copy behavior of shared_ptr is much more normal:
void F () {
...
Std::tr1::shared_ptr<investment> pInv1 (Createinvestment ());
PINV1 point to Createinvestment return object
Std::tr1::shared_ptr<investment> pInv2 (PINV1);
PInv1 and PInv2 point to the same object
PINV1 = PInv2;
Ditto, without any change
...
}//PInv1 and PInv2 are destroyed, and the objects they point to are also automatically destroyed
Because of the TR1::SHARED_PTR replication behavior "As expected", they can be used in STL containers and other contexts where "auto_ptr non-orthodox replication behavior does not apply".
Both auto_ptr and tr1::shared_ptr do delete instead of delete[in their destructor (see Clause 16). That means using auto_ptr or tr1::shared_ on a dynamically allocated array PTR is a bad idea.
Std::auto_ptr<std::string> APs (new STD::STRING[10]); Bad idea
Std::tr1::shared_ptr<int> SPI (new int[1024]); Bad idea
It can be found that something like auto_ptr or tr1::shared_ptr is not specifically designed for the C + + dynamic allocation array, because vectors and strings can almost always replace dynamically allocated arrays.
In addition, it must be noted that Createinvestment returns an "unprocessed pointer" (raw pointer), which is simply a death invitation to a resource leak because the user is apt to forget to call Delete on the pointer. (Even if you use Auto_ptr or tr1::shared_ptr to perform the delete, you must first remember to store the return value of createinvestment in a smart pointer object). To wrestle with this problem, The first thing you need to do is interface modification to createinvestment, which is the article 18.
Note :
To prevent resource leaks, use the Raii object, which obtains resources in constructors and frees resources in destructors.
The two commonly used RAII classes are tr1::shared_ptr and auto_ptr respectively. The former is usually a better choice, because its copy behavior is more intuitive. If you select Auto_ptr, the copy action causes it (copied) to point to null.
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
Effective c++--Clause 13 (chapter 3rd)