Clause 9: select carefully in the delete option

Source: Internet
Author: User
Suppose you have a standard STL container, C, which contains int,
Container <int> C;
And you want to remove all objects whose values are 1963 in C. Surprisingly, the method for completing this task varies depending on the container type: No
One method is generic.
If you have a continuous memory container (vector, deque, or string-see clause 1), the best method is erase-Remove.
See Clause 32 ):
C. Erase (remove (C. Begin (), C. End (), 1963), // when C is a vector, string
C. End (); // or deque,
// Erase-Remove
// Is an element that removes a specific value.
// The best method
This method is also suitable for the list, but, as explained in cla44, the remove function of the List member function is more efficient:
C. Remove (1963); // when C is a list,
// Remove the member function is to remove
// The best method for elements with specific values
When C is a standard associated container (that is, set, Multiset, map, or multimap), it is totally wrong to use anything called remove.
Such a container does not have a member function called remove and uses remove Algorithm Container values may be overwritten (see cla32), potentially damaging
Container. (For details about such damages, refer to Clause 22, which also explains why you try to use remove on map and multimap.
It cannot be compiled, but it may not be compiled if you try to use it on set or Multiset .)
No. For associated containers, the proper solution to the problem is to call erase:
Clause 9: select carefully in the delete option
C. Erase (1963); // when C is a standard associated container
// Erase member functions are removed
// The best method for elements with specific values
This is not only correct, but also highly efficient. It takes only a logarithm of time. (Delete-based technology of sequence containers requires linear time .) And close
The erase member functions of the container have the advantage of equivalence rather than equality. Clause 19 explains the importance of this difference.
Let's modify this question a little bit now. Instead of Removing each object with a specific value from C, let's remove the following formula (see Terms and Conditions)
39) returns true for each object:
Bool badvalue (int x); // returns whether X is "bad"
For a sequence container (vector, String, deque, and list), all we need to do is replace each remove with remove_if, and then complete
Now:
C. Erase (remove_if (C. Begin (), C. End (), badvalue), // when C is a vector, string
C. End (); // or deque is removed
// Badvalue returns true
// The best method for Object
C. remove_if (badvalue); // This is removed when C is a list.
// Badvalue returns true
// The best method for Object
For standard associated containers, it is not very straightforward. There are two ways to solve this problem: one is easier to code and the other is more efficient. "More
The solution is easy but less efficient. Use remove_copy_if to copy the value we need to a new container, and then copy the content of the original container and
New exchange:
Assoccontainer <int> C; // C is now
... // Standard associated container
Assoccontainer <int> goodvalues; // used to hold data that is not deleted
// Temporary container of the value
Remove_copy_if (C. Begin (), C. End (), // do not delete the copy from C
Inserter (goodvalues, // value
Goodvalues. End (), // goodvalues
Badvalue );
C. Swap (goodvalues); // exchange C and goodvalues
Clause 9: select carefully in the delete option
// Content
The disadvantage of this method is that it copies all elements that are not deleted, and the overhead of such copying may be greater than what we are interested in.
We can avoid that bill by directly deleting elements from the original container. However, because the associated container does not provide a member letter similar to remove_if
So we have to write a loop to iterate the elements in C, and delete the elements as before.
It seems that this task is very simple, and in fact, Code It is also very simple. Unfortunately, code that works correctly rarely comes to mind
Code. For example, there are many Program First thought:
Assoccontainer <int> C;
...
For (assoccontainer <int>: iterator I = C. Begin (); // clear and straightforward
I! = C. End (); // used in case of loopholes
++ I) {// Delete the badvalue in C and return the true value.
If (badvalue (* I) c. Erase (I); // code of each element
} // Do not do this!
Alas, this has undefined behavior. When an element of the container is deleted, all iterators pointing to that element become invalid. When C. Erase (I) returns
The I has expired. It is a bad message for this loop, because after erase returns, I uses the ++ I auto-incrementing Part Of The for loop.
To avoid this problem, we must ensure that the iterator of the next element in C is obtained before calling erase. The easiest way is when we call
Use post-increment on I:
Assoccontainer <int> C;
...
For (assoccontainer <int>: iterator I = C. Begin (); // the third part of the For Loop
I! = C. End (); // It is empty; I is now below
/* Nothing */) {// auto-Increment
If (badvalue (* I) c. Erase (I ++); // for bad values, set the current
Else ++ I; // I is passed to erase, and then
} // Increase I as a side effect;
// For a good value,
// Add only I
This method of calling erase can work, because the expression I ++ value is the old value of I, but as a side effect, I is increased. Therefore, we
The old value (not added) is passed to erase, But I has automatically increased before erase starts execution. That's exactly what we want. As I said
Clause 9: select carefully in the delete option
The code is very simple, but not what most Programmers think of when they first try.
Now let's further modify the problem. Not only does the badvalue deletion return true for each element, but when an element is deleted, we also
You want to write a message to a log file.
For associated containers, this is much easier to say, because you only need to make a slight modification to the loop we just developed:
Ofstream logfile; // log file to be written
Assoccontainer <int> C;
...
For (assoccontainer <int>: iterator I = C. Begin (); // The loop condition is the same as the previous one.
I! = C. End ();){
If (badvalue (* I )){
Logfile <"erasing" <* I <'\ n'; // write a log file
C. Erase (I ++); // deletes an element.
}
Else ++ I;
}
Now we are troubled by vector, string, and deque. We can no longer use erase-remove, because there is no way for erase or
Remove to write a log file. Moreover, we cannot use the loop developed for the associated container, because it generates
Defined behavior! Remember that for such containers, calling erase not only invalidates all iterators pointing to the deleted elements, but also causes
All iterators of are invalid. In our case, it includes all the iterators after I. We write I ++, ++ I, or anything else you can think.
It is useless to the West, because it cannot make the iterator effective.
We must adopt different strategies for vector, string, and deque. In particular, we must use the returned values of erase. The returned value is exactly me.
What we need: Once the deletion is complete, it is the effective iterator pointing to the elements following the deleted elements. In other words, we write:
For (seqcontainer <int >:: iterator I = C. Begin ();
I! = C. End ();){
If (badvalue (* I )){
Logfile <"erasing" <* I <'\ n ';
I = C. Erase (I); // return the value of erase
} // Assign to I to keep I valid
Else
++ I;
}
Clause 9: select carefully in the delete option
This works well, but is only used for standard sequence containers. Due to a possible argument (Clause 5 has done), the Standard Association container's erase
The return type is void [1]. For those containers, you must use the "post-incrementing iterator you want to pass to erase" technology. (By The Way,
The difference between encoding for the serial container and encoding for the associated container is an example of the general lack of considerations for writing container-independent code --
See Clause 2 .)
To avoid wondering what the proper method of list is, it turns out that for iteration and deletion, You can associate like vector/string/deque
The container treats the list in the same way. Both methods can work on the list.
If we observe all the things mentioned in these terms, we come to the following conclusions:
● Remove all objects with specific values in a container:
If the container is a vector, string, or deque, use erase-Remove.
If the container is list, use list: Remove.
If the container is a standard associated container, use its erase member function.
● Remove all objects in a container that meet a specific criterion:
If the container is a vector, string, or deque, use a erase-remove_if.
If the container is list, use list: remove_if.
If the container is a standard associated container, use remove_copy_if and swap, or write a loop to traverse the container elements.
When it is passed to erase, remember to increment it later.
● Do something in the loop (except Delete objects ):
If the container is a standard sequence container, write a loop to traverse the container elements. Whenever erase is called, remember to use its return value to update you.
.
If the container is a standard associated container, write a loop to traverse the container elements. When you pass the iterator to erase, remember to increment it later.
As you can see, there are more effective ways to delete container elements than simply calling erase. The best way to solve the problem depends on how you
Identify which object is to be removed, the type of the container that stores them, and what else you want to do when you delete them (if there is
). As long as you are careful and pay attention to the suggestions in these terms, you will have no effort. If you are not careful, you will be willing to generate unnecessary and inefficient agents.
The risk of code or undefined behavior.
Clause 9: select carefully in the delete option
[1] This is only true for the erase form with the real parameters of the iterator. The associated container also provides an erase form with a value.
Returns the number of deleted elements. But here, we only care about deleting things through the iterator.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.