"STL Source Code Analysis" (3) - Iterator and traits programming

1. Iterator

In STL programming, the container and the algorithm are independent of each other. The container is the data, and the algorithm provides the operation on the data. In the process of the algorithm operation, the iterator is used, and the iterator can be regarded as the bridge between the container and the algorithm.
insert image description here

2. Iterator design pattern

In design patterns, there is a dedicated iterator pattern. Described as follows: A method that can access each element in the question sequentially, without exposing the internal representation.
In the STL programming structure, iterator is a template class. Iterator is widely used in STL. Through iterator, container and algorithm can be organically bound together, as long as the algorithm is given different iterators, such as vectot ::iterator, list::iterator, std::find(), you can find different containers without designing a version of each container.

3. Smart pointer

STL is the product of the idea of ​​generic programming, and it is produced under the guidance of the idea of ​​generic programming. Specifically, iterators in the STL apply a generic algorithm to a container, providing the algorithm with a tool to access the container, and the iterator plays this role.
Iteration is actually a kind of smart pointer, which has the characteristics of a general pointer and can perform * and -> operations in alignment.

template<typename T>
class ListIterator {
    
    //mylist迭代器
public:
    ListIterator(T *p = 0) : m_ptr(p){
    
    } //构造函数
    T& operator*() const {
    
     return *m_ptr;}  //取值,即dereference
    T* operator->() const {
    
     return m_ptr;} //成员访问,即member access
    //...
};

However, when traversing the container, it is inevitable to have some understanding of the inside of the traversal container. Therefore, simply leave the development of the iterator to the container designer. In this way, all the implementation details can be sealed from the user, so every time An STL container has its own iterator.
Advantages:
(1) Don't worry about memory leaks (similar to smart pointers, the destructor releases memory)
(2) For list, the next element is not taken by auto-increment but by the next pointer, using smart pointers to achieve auto-increment and auto-increment reduce, so as to achieve a unified interface.

4. Template parameter deduction

In an algorithm, you need to use variable types when you define intermediate variables or return values. C++ does not provide the typeof() interface and cannot be obtained directly.
(C++ provides the typeid() operator, which can only get the name of the type and cannot declare variables)
Parameter deduction of function template:

template <class I>
inline void func(I iter)
{
    
    
	func_imp(iter, *iter); //传入iter和iter所指的值,class自动推导
}
void func_imp(I iter, T t)
{
    
    
	T tmp;  //T就是迭代器所指的数据类型
	...//
}
int main()
{
    
    
	int i;
	func(&i);
}

Through multi-layer iteration, T can be derived, but it has great limitations. For example, it is hoped that func() returns the value type() type return value of the iterator, but the template parameter deduction mechanism can only deduce the parameters, but cannot deduce the return value of the function Types of.

5. Declare inline categories

The type of the object pointed to by the above iterator is called the value type of the iterator.
Add an embedded type (typedof) to the deduction mechanism, define an alias for the specified object, and then get it directly:

template<typename T>
{
    
    
class MyIter{
    
    
public:
	typedef T value_type;//内嵌类型声明
	MyIter(T *p = 0):m_ptr(p) {
    
    }
	T & operator*() const{
    
    return * m_ptr;}
	}
private:
	T * m_ptr;
}
//以迭代器所指对象的类型作为返回类型
//注意typename是必须的,它告诉编译器这是一个类型
template<typename MyIter>
typename Myiter::value_type Func(MyIter iter)
{
    
    
	return *iter;
}
int main(int argc, const char *argv[])
{
    
    
	Myiter<int> iter(new int(600));
	std::cout<<Func(iter)<<std::endl; //print => 666
}

In the above solution, not all iterators are class types, and native pointers are also iterators. Since native pointers are not class types, there is no way to set an embedded category for them.
func is a generic algorithm, then it absolutely must accept raw pointers as iterators, the following code will fail to compile:

int *p = new int (5);
cout<<func(p)<<endl;

6. Partial specializiation

The so-called partial specialization means that if a class template has more than one template parameter, we can specialize one (or more, but not all) templates, for example:

tempalte<class T>
class C{
    
    } //通用版本
template<class T>
class C<T*>{
    
     } //仅仅适用于T为原生指针的情况,泛化版本的限定版

The so-called specialization is the processing of special cases. The first class is generalized programming, T can be any type, and the second version is the generalized version, which is a special case of the first class, only for raw pointers.

6.1 Coping with native pointers - feature "extraction" traits

STL has designed a special "extraction" class, which specifically "extracts" the characteristics of iterators, and value type is one of the characteristics of iterators:

template<class _Tp>
struct iterator_traits<_Tp*>
{
    
    
typedef ptrdiff_t difference_type;
typedef typename _Tp::value_type value_type;
... 
}

Changes before and after adding the extractor:

template<class Iterator>//萃取前
typename Iterator::value_type func(Iterator iter)
{
    
    
	return *iter;
}
通过iterator_traits作用后的版本
template<class Iterator>//萃取后
typename iterator_traits<Iterator>::value_type func(Iterator iter)
{
    
    
	return *iter;
}

Through encapsulation, the specialization of the template can be supported by the conversion of the class template to support the version of the native pointer! In this way, iterator_traits::value_type can work regardless of smart pointers or native pointers, solving the above problems.

6.2 const biased specialization

The traits template class that adds intermediate layer conversion through partial specialization can support native pointers and iterators. The processing of constant pointers is as follows:

iterator_traits<const int*>::value_type  // 获得的 value_type 是 const int,而不是 int
//const变量只能初始化而不能赋值,如下例将报错:
template<typename Iterator>
typename iterator_traits<iterator>::value_type func(Iterator iter){
    
    
typename iterator_traits<iterator>::value_type tmp;
temp = * iter; //编译error
}
//偏特化:
template<typename T>
struct iterator_traits<const T *>
{
    
    
	typedef T value_type; //得到T而不是const T
}

7. Traits programming techniques

The traits programming technique is to solve the problem of obtaining the native pointer of the iterator type by adding an intermediate template class. Using an intermediate layer to fix the form of func, the repetitive code is greatly reduced. What to do is to specialize iterator_traits to support pointer and const pointer.
The passed T is the class, ask T::value_type, otherwise enter the specialized version, T is the value_type.
Summary: The core knowledge lies in the template parameter deduction mechanism and embedded type definition. In order to handle the special iterator such as raw pointer, a partial specialization mechanism is introduced. Traits are like a "feature extraction machine", putting the iterator into it , you can extract the characteristics of iterators.

8. Types and classifications of iterators

8.1 Types of iterators

There are five common types of
iterators: value_type: The type of the object pointed to by the iterator, and the native pointer is also an iterator. For the native pointer int*, int is the type of the object pointed to by the pointer, which is the so-called type_value.
difference_type: used to indicate the distance between two iterators. For native pointers, STL uses C++'s built-in ptrdiff_t as the difference_type of native pointers.
reference_type: Refers to the reference of the type of the object pointed to by the iterator. The reference_type is generally used in the overloading of the * operator of the iterator. If the value_type is T, the corresponding reference_type is T&; if the value_type is const T, the corresponding reference_type is const T&.
pointer_type: is the corresponding pointer type. For pointers, the most commonly used functions are operator * and operator -> two operators.
iterator_category: The function is to identify the movement characteristics of the iterator and the operations that can be performed on the iterator. It is divided into 5 categories, Input_Iterator, Output_Iterator, Forward_Iterator, Bidirectional_Iterator, Random_Access Iterator.

template<typename Category, typename T, typename Distance = ptrdiff_t, typename Pointer = T*, typenmame Referencee = T&>
struct iterator//迭代器的定义
{
    
    
	typedef Category iterator_category;
	typedef T value_type;
	typedef Distance difference_type;
	typedef Pointer pointer;
	typedef Reference reference;
}

The iterator class does not contain any member variables, only the definition of the type, so no additional burden is added. Since the latter three types have default values, they do not need to be provided during inheritance. This class is mainly used for inheritance, and these five categories must be included in the implementation.
The design of the corresponding iterator extractor is as follows:

template<typename I>
struct iterator_traits
{
    
    
	typedef I::iterator_category iterator_category;
	typedef I::value_type value_type;
	typedef I::difference_type difference_type;
	typedef I::pointer pointer;
	typedef I::reference reference
};
//需要针对指针和const指针设计特化版本

8.2 Classification of Iterators

Input Iterator: This iterator does not allow modification of the pointed-to object and is read-only. Support ==,! =, ++, , -> and other operations.
Output Iterator: This iterator can perform write-only operations, and supports ++,
etc. operations.
Forward Iterator: Allows the algorithm to perform read and write operations in the space formed by the iterator, and can only move in one direction, one step at a time.
Bidirectional Iterator: It can move in both directions, and other functions are the same as the former.
Random_Access_Iterator: Random access, including all operations of Iterator.
insert image description here

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324467066&siteId=291194637