Cla44: Use a member function instead of an algorithm of the same name.
Some containers have member functions with the same name as STL algorithms. Associated containers provide count, find, lower_bound, upper_bound, and limit _range, while list provides remove, remove_if, unique, sort, merge, and reverse. In most cases, you should use member functions instead of algorithms. There are two reasons for doing so. First, member functions are faster. Second, they are better integrated with containers (especially associated containers) than algorithms ). That's because algorithms with the same name and member functions are generally not the same.
We started with an experiment on the associated container. If there is a set <int>, it stores 1 million elements, and you want to find the first occurrence location of element 727 (if any ). There are two most natural ways to perform a search:
Set <int> S; // create a set and put 1,000,000 pieces of data... // set <int >:: iterator I = S. find (727); // use the find member function if (I! = S. end ())... set <int>: iterator I = find (S. begin (), S. end (), 727); // use the find algorithm if (I! = S. End ())...
The running of the find member function takes a logarithm of time, so whether or not 727 exists in this set, set: Find only needs to execute a comparison of up to 40 times to find it, but generally only needs 20 times. On the contrary, the find algorithm takes linear time to run, so if 727 is not in this set, it needs to perform 1,000,000 comparisons. Even if 727 is in this set, an average of 500,000 comparisons are required to find it. The efficiency score is as follows:
Find members: About 40 (worst case) to about 20 (average case) Find algorithm: 1,000,000 (worst case) to 500,000 (average case)
As in a golf competition, a low score wins. As you can see, there is nothing to say about the results of this competition.
I must be cautious about the number of comparisons required by the find member function because it depends on the implementation of the associated container. The vast majority of implementations are the red and black trees used-one of the balance trees-with an imbalance of up to 2. In this implementation, the maximum number of comparisons required to search the set with 1 million elements is 38. However, for the vast majority of search cases, only 22 or more times are required. The implementation of a fully balanced tree does not need to be compared more than 21 times. However, in practice, the efficiency of a fully balanced tree is generally not as high as that of a red-black tree. This is why most STL implementations use the red/black tree.
Efficiency is not the only difference between the find member function and the find algorithm. As explained in Clause 19, the STL algorithm checks whether two objects are the same by checking whether they are equal, while the associated container uses equivalence) to test their "identity ". Therefore, the find algorithm uses equal values for searching 727, while the find member functions use equal values. The difference between equality and equivalence may lead to the difference between successful search and unsuccessful search. For example, Clause 19 demonstrates the use of the find algorithm to successfully search for a container that fails to search for the associated container! Therefore, if you use an associated container, you should try to use the find, Count, lower_bound, and so on in the form of member functions, rather than the generic algorithm with the same name, because these member function versions provide the same behavior as other member functions. Because of the differences between equality and equivalence, generic algorithms cannot provide such consistent behavior.
This difference is particularly evident for map and multimap, because they hold object pairs (pair objects), and their member functions only care about the key part of object pairs. Therefore, the Count member function only counts the number of object pairs that match the key value (the so-called "match" is the case of equivalence detection); the value part of the object pair is ignored. The same applies to member functions such as find, lower_bound, upper_bound, and interval _range. However, if you use the Count algorithm, its search will be based on all the components of (a) equal and (B) object pairs; the same applies to generic algorithms such as find and lower_bound. To make generic algorithms focus only on the key part of the object pair, you must jump out of the limit described in Article 23 (where the equivalent test instead of the equivalent test method is introduced ).
On the other hand, if you are really concerned about efficiency, you can use the technique in Clause 23 and the logarithm time search algorithm mentioned in Clause 34. Compared with performance improvement, this is only a small price. Furthermore, if you really care about efficiency, you should consider non-standard hash containers (described in Clause 25). However, you will face the difference between equality and equivalence again.
For standard associated containers, selecting a member function instead of an algorithm with the same name has several advantages. First, you get the performance of logarithm time rather than linear time. Second, you can determine that the two elements "same" are equivalent, which is the default definition of the associated container. Third, when manipulating map and multimap, You can automatically process only key-value pairs instead of (key-value) pairs. These three points give priority to the use of the member function perfect armor.
Let's go to the List member functions with the same name as the algorithm. Almost all the stories here are about efficiency. Each list-specific algorithm (remove, remove_if, unique, sort, merge, and reverse) needs to copy objects, but the list-specific version does not copy anything; they are just simple pointers to nodes connected to the list. The complexity of algorithms and member functions is the same. However, if the pointer is less expensive than copying an object, the List version should provide better performance.
It is important to keep this in mind: the behavior of List member functions is often different from that of their algorithm brothers. As explained in cla32, if you really want to clear objects from the container, after calling the remove, remove_if, and unique algorithms, you must call the erase function immediately; however, the remove, remove_if, and unique member functions of the list really remove the elements and do not need to call erase later.
An important difference between the sort algorithm and the sort member functions of the List algorithm is that the former cannot be used as a list. As a pure bidirectional iterator, the list iterator cannot be passed to the sort algorithm. There is also a huge difference between the merge algorithm and the merge member functions of the list. This algorithm is restricted to modifying the source range, but list: Merge always modifies its host list.
So, you understand. When selecting between STL algorithms and container member functions with the same name, you should try your best to use member functions. It is almost certainly more efficient, and it looks better integrated with the usual behavior of the container.