Cla33: Beware of using remove-like algorithms on Pointer containers
You are managing a bunch of dynamically allocated widgets, each of which may pass the test. You save the result pointer in a vector:
Class widget {public :... bool iscertified () const; // check whether this widget has passed ...}; vector <widget *> V; // create a vector and use... // dynamically assigned widgetv. push_back (new widget); // pointer Filling
After working with V for a period of time, you decided to remove the widgets that did not pass the test, because you no longer need them. Remember the warning in Clause 43. Use an algorithm call instead of an explicit loop and a description of the relation between remove and erase. You will naturally think of turning to erase-Remove, although remove_if:
V. erase (remove_if (v. begin (), V. end (), // Delete not1 (mem_fun (& Widget: iscertified) that has not passed the test), // widget pointer v. end (); // information about mem_fun // See Clause 41
Suddenly you begin to worry about erase calls, Because you vaguely remember clause 7's discussion about how to destroy a pointer in a container will not delete anything pointed by the pointer. This is a reasonable concern, but it is too late here. When you call erase, it is very likely that you have leaked the resource. Worry about erase, yes, but first, worry about remove_if.
Let's assume that V looks like this before remove_if is called, and I have pointed out the widgets that have not passed the Verification:
After remove_if is called, generally V looks like this (including the iterator returned from remove_if ):
If you do not understand this conversion, switch to Clause 32 because it accurately explains what remove_if -- has done by calling remove -- or in this example.
The reason for resource leaks is now clear. The "deleted" pointer pointing to widgets B and C is overwritten by the "undeleted" pointer next to the vector. Nothing points to two unverified widgets, and they are not deleted, and their memory and other resources are leaked.
Once remove_if and erase are returned, it looks like this:
This results in resource leakage, especially. Now you know why you should try to avoid using remove and similar algorithms (that is, remove_if and unique) on the dynamically allocated pointer container ). In many cases, you will find that the Partition Algorithm (see section 31) is a reasonable alternative.
If you cannot avoid using remove on such a container, one way to eliminate this problem is to delete pointers and set them to null before applying erase-Remove, remove all null pointers in the container:
Void delandnullifyuncertified (widget * & pwidget) // If * pwidget is a {// If the widget is not verified, if (! Pwidget-> iscertified () {// Delete pointer Delete pwidget; // and set it to null pwidget = 0 ;}} for_each (v. begin (), V. end (), // point all to delandnullifyuncertified that has not passed the verification widget); // Delete the pointer and set it to null v. erase (remove (v. begin (), V. end (), // remove the NULL pointer static_cast from v <widget *> (0), // 0 must be mapped to a pointer, V. end (); // enable C ++ to // correctly introduce the type of the third parameter to remove. //
Of course, this assumes that the vector does not hold any NULL pointer you want to keep. If so, you may have to write a loop to delete the pointer in your way. When you traverse a container, there are some subtle points to note when deleting elements from the container. Before considering that method, make sure you have read Article 9.
If you replace the pointer container with the smart pointer container that executes the reference count, the related deletion difficulties will not exist. You can directly use erase-Remove:
Template <typename T> // rcsp = "reference Count class rcsp {...}; // smart pointer "typedef rcsp <widget> rcspw; // rcspw =" rcsp to widget "vector <rcspw> V; // create a vector and use dynamic... // allocate the widget's v. push_back (rcspw (new widget); // fill it with a smart pointer... v. erase (remove_if (v. begin (), V. end (), // not1 (mem_fun (& Widget: iscertified) not verified by erase), // widget pointer v. end ());//No resource leakage
To do this, you must implicitly convert your smart pointer type (such as rcsp <widget>) to the corresponding built-in pointer type (such as widget *). This is because containers hold smart pointers, but the called member functions (such as Widget: iscertified) need built-in pointers. If there is no implicit conversion, your compiler will protest.
If no reference counting smart pointer template exists in your toolbox, you should get the shared_ptr template from the boost library. For more information about boost, see article 50.
No matter how you choose a container that handles the Dynamic Allocation of pointers, You can manually delete and discard pointers or some of your own technologies by referencing the counting smart pointer, before calling a remove-like algorithm, the guiding significance of these terms remains the same: Beware of using remove-like algorithms on Pointer containers. Those who do not pay attention to this suggestion can only cause resource leakage.