STL is a generic programming (generic programming). Object-oriented programming focuses on the data aspect, whereas generic programming focuses on algorithms. The common denominator between them is abstraction and the creation of reusable code, and their ideas are decidedly different.
Generic programming is designed to write code that is independent of the data type.
16.4.1 why iterators are used
Understanding iterators is the key to understanding STL. The template makes the algorithm independent of the stored data type, and iterates over it to make the algorithm independent of the type of container used. Therefore, they are an important part of the STL common approach.
To understand why iterators are needed, let's look at how to implement the Find function for two different data manifestations, and then see how to promote this approach. Let's start by looking at a function that searches for a specific value in a double array, and you can write the function like this:
Double * Find_ar (double * ar, int n, const double & val)
{
for (int i = 0; i < n; i + +)
if (ar[i] = = val)
Return &ar[i];
return 0; Or, in c++11, return nullptr;
}
If the function finds such a value in the array, it returns the address of the value in the array, otherwise a null pointer is returned. The function uses subscripts to facilitate the array. You can use a template to generalize this algorithm to an array of any type that contains the = = operator. In spite of this, the algorithm is still associated with a particular data structure (array).
Let's look at another data structure-the list of links (the 12th chapter implements the queue class using a linked list). A linked list consists of a node structure that is connected together:
struct Node
{
Double item;
Node * P_NEXT;
};
Suppose you have a pointer to the first node of the list, each node's p_next pointer points to the next node, and the P_next pointer of the last node of the list is set to 0, you can write the Find_ll () function like this:
node* Find_ll (Node * head, const double & val)
{
Node * START;
for (start = head; start! = 0; start = start->p_next)
if (Start->item = = val)
return start;
return 0;
}
Similarly, you can use a template to push the algorithm to a linked list of any data type that supports the = = operator. However, this algorithm is also associated with a particular data structure-the linked list.
The algorithm for the two find functions is different from the implementation details: one uses the array index to facilitate the element, and the other resets the start to Start->p_next. But from the crown, the two algorithms are the same: compare the values sequentially to each value in the container and know where to find the match.
Generic programming is designed to use the same find function to work with arrays, linked lists, or any other container type. The function is not only independent of the data types stored in the container, but also independent of the data structure of the container itself. The template provides a generic representation of the data type stored in the container, so it is also necessary to facilitate a common representation of the values in the container, which is formally represented by the iterator.
To implement the Find function, the iterator should have the characteristics:
* You should be able to access the value that it references by iterating over it and performing dereferencing operations. That is, if P is an iterative one, the *p should be defined.
* Should be able to assign one iteration to another. That is, if both P and Q are iterators, the expression p=q should be defined.
* You should be able to compare one iterator to another to see if they are equal. That is, if both P and Q are iterated, the p==q and p!=q should be defined.
* You should be able to iterate over all the elements in its convenience container, which can be achieved by defining ++p and p++ for the iteration of its p.
Regular pointers can meet the requirements of iterators, so you can rewrite the Find_arr () function like this:
typedef double * iterator;
Iterator Find_ar (iterator ar, int n, const double double & val)
{
for (int i = 0; i < n; i++, ar++)
if (*ar = = val)
return ar;
return 0;
}
The function parameter can then be modified to accept two pointer parameters, one pointing to the starting position of the array and the other to the super-tail of the array, and the function can indicate that the value is not found by returning a tail pointer. The following version of Find_ar () has completed these modifications:
typedef double * iterator;
Iterator Find_ar (iterator begin, iterator end, const double & val)
{
Iterator ar;
for (AR = begin; AR! = end; ar++)
if (*ar = = Vale)
return ar;
return end; Indicates Val not found
}
For the Find_ll () function, you can define an iterator class that defines the operators * and + +:
struct Node
{
Double item;
Node * P_NEXT;
};
Class iterator
{
Node * PT;
Public
ITERAOTR ():p t (0) {}
Iterator (Node * pn): PT (n) {}
Double operator* () {return pt->item;}
iterator& operator++ ()//For ++it
{
PT = pt->next;
return *this;
}
Iterator oprator++ (int)//For it++
{
iterator tmp = *this;
PT = pt->next;
return TMP;
}
... oprator== (), operator!= (), etc.
};
To differentiate between the prefix version and the suffix version of the + + operator, C + + uses operator++ as the prefix version and operator++ (int) as the suffix version: The parameters are never used, so it is not the same as specifying their name.
The point here is not how to define the iterator class, but with such a class, the second find function can be written like this:
Iterator Find_ll (iterator head, Const double & val)
{
Iterator start;
for (start = head; start! = 0; + + start)
if (*start = = val)
return start;
return 0;
}
The STL follows the method described above. First, each container class (vector, list, deque, and so on) defines the corresponding iteration of its type. For one of these classes, the iteration may be a pointer, and for another class, Ken is the object. Regardless of how it is implemented, iterations will provide the required actions, such as * and + + (some of the required operations may be more than others). Second, each container class has an ultra-micro tag that, when iterated over to the last value beyond the container, is assigned the value to iterate over it. Each container class has the Begin () and end () methods, and they return a pointer to the first element of the container and the iteration of the trailing position. Each container class uses the + + operation, allowing the iteration to point from the first element to the micro position, thus facilitating each element in the container.
STL writes the same code by defining the appropriate iterations for each class, and firing the class in a uniform style, able to represent the internal, decidedly different container.
The new automatic type inference using c++11 can be further simplified: for vectors or lists, you can use the following code:
for (Auto PR = Scores.begin (); PR! = Scores.end (); PR + +)
cout << *pr << Endl;
Z in fact, as a kind of wind, it is best to avoid using iterations directly, and should use STL functions (such as for_each ()) to handle the details as much as possible. You can also use the C++11 new range-based for loop:
for (auto x:scores) cout << x << Endl;
Summarize the STL method: First of all, the method of handling containers, should be used as far as possible to express the algorithm as a generic, independent of the data type and container class. In order to make the general algorithm suitable for the situation, we should define the iteration which can satisfy the requirement of the algorithm and add the requirement to the container design. Based on the requirements of the algorithm, the design of the basic iterative features and container characteristics.
16.4.2 iterator Type
The STL defines five types of iterators: an input iterator, an output iterator, a forward iterator, a bidirectional iterator, and a random iterator.
16.4.3 iterator Hierarchy
......
16.4.4 concepts, improvements and models
......
16.4.5 container Type
The previous 11 container types were: Deque,list,queue,priority_queue,stack,vector,map,multimap,set,multiset,bitset
C + + has new forward_list,unordered_map,unordered_multimap,unordered_set,unordered_multiset and does not treat bitset as a container. and treat it as a separate category.
"Here is a description of each kind of container *"
C + + Primer Plus 16.4 Generic Programming Learning Notes