[c++] STL Source Analysis: Iterator and Trats Programming Skills

Posted by Haktar on Sat, 27 Jul 2019 09:41:51 +0200

Reference book STL Source Analysis

STL mainly learns the following parts:
I. Containers
1. Sequential containers
            vector  list  deque
2. Associated Container, Red-Black Tree BST
set multiset map multimap//observer mode
3. Container adapter deque
            stack   queue  priority_queue
II. Generic Algorithms
        find sort  
III. Iterators
Container: iterator reverse_iterator
               const_iterator  const_reverse_iterator
Five iterators
Input-Output Forward Bidirectional Random Access
Three types
1. Reverse
2. Insertion type
3. Flow pattern
4. Function object imitation function //greater less
Two species
Univariate function object
2. Binary Function Objects
V. Adapter bind2nd not1
            
VI. Space Configurator
Level 1 Space Configurator
2. Secondary Space Configurator

----------------------------------------

Preface: What does this blog want to write?

Following the idea of STL Source Analysis, I design iterators in list and vector, encounter problems, solve problems, and then summarize and analyze the source code.

But we need to understand the template, because STL uses a large number of templates, the concept of template is simple to use, template specialization (partial specialization, complete specialization); the type of iterator, the relationship between several iterators, analysis of the source code iterator, extraction of traits programming.

Summary of the book: Read it several times to understand:

It is the responsibility of the iterator to design the corresponding type of iterator.
It is the responsibility of the container to design appropriate iterators.
Only the container itself knows what iterators should be designed to visit itself and perform the various behaviors (forward, backward, value, member) that iterators should have.
As for the algorithm, it can be developed independently of the container iterator, as long as the iterator is designed as the external interface.   
Trats programming techniques are widely used in STL. It makes use of "embedded gender" programming skills and compiler template parameter derivation function to enhance the ability of type authentication that c++ fails to provide.
Make up for the fact that c++ is not a strongly typed language.
Understanding traits programming is the key to open STL source profiling.

I. Relations of several iterators:


1. The corresponding type of iterator:

"What is the iterator type? Answer: The type of object that an iterator refers to is one of them (that is, the type of object that an iterator refers to)"

There are five types of iterators:

value_type * Value type: Type of object referred to by iterator
difference_type: Used to indicate the distance between two iterators
reference_type.Reference type:
Pointer type const_pointer_type Constant pointer type
iterator_category: Iterator type (divided into the following five types)

STL Source Analysis is a book written by Taiwan compatriots, so some words in the book feel awkward to read.
For example, "Type of Object" is "Type of Object" in the book.

  

2. Five Iterators

Iterators are classified into five categories according to their movement characteristics and action actions.
input_iterator
output iterator
Forward Iterator
Bidirectional Iterator
Random Access Iterator

Relationships among five iterators: as shown in Figure 126 of STL Source Analysis


The arrows in the figure represent inheritance relationships, and you can see the hierarchical inheritance relationships of the five iterators.

What is common inheritance? "One" means! What is private inheritance? "Combination"...

3. Iterators in containers:

hashtable slist: forward iterator
Listmap set: bidirectional iterator
vector dequeue: Random iterator
(Understandably, the iterator in the container is three of the five iterators, because the forward iterator inherits the input and output iterators, so these three are enough.)

(Or that sentence: "It is the responsibility of the iterator to design the corresponding type of iterator. It is the responsibility of the container to design an appropriate iterator.
 

2. Designing iterators by oneself:

 

1. Define itreator as a tag category

//Create your own header file iterator.h 

struct input_iterator_tag{};
struct output_iterator_tag{};
struct forward_iterator_tag :  public input_iterator_tag { };
struct bidirectional_iterator_tag : public forward_iterator_tag { };
struct random_access_iterator_tag : public bidirectional_iterator_tag { };

   
2. Define the iterator type:

        //Written in iterator.h
        /* The following template outlines the template type:
        _Cate : iterator_category         Iterator types (divided into the following five types)
        _Ty: value_type                  Value type: The type of the object that the iterator refers to
        _Dist:difference_type          Difference type: Used to indicate the distance between two iterators
        _P : pointer_type                Pointer type const_pointer_type constant pointer type
        _ref:reference_type           Reference type:
        */
        template<class _Cate,class _Ty,class _Dist class _P = _Ty*,class _Ref = _Ty&> //Defining an iterator requires five corresponding types: an iterator type value difference pointer reference
        struct iterator
        {
            //Rename typedef for five corresponding types of iterators:
            typedef _Cate iterator_category;
            typedef _Ty   value_type;
            typedef _Dist difference_type;
            typedef _P    pointer;
            typedef _Ref  reference;
        }    

3. Define the iterator in the container: bidirectional random forward:

Designing three classes, inheriting iterator classes altogether, and giving the logo of iterator

        //Written in iterator.h
        template<class _Ty,class _Dist> //Forward iterator
        class _Forit:public iterator<forward_iterator_tag,_Ty,_Dist>
        {};
        
        template<class _Ty,class _Dist>  //Bidirectional Iterator
        class _BIDrit:public iterator<bidirectional_iterator_tag,_Ty,_Dist>
        {};
        
        template<class _Ty,class _Dist>   //RadomAccessIterator
        class _Ranrit:public iterator<random_access_iterator_tag,_Ty,_Dist>
        {};

    
4. Designing your own list

Of course, it's not complete here, it's only about iterators; there are many functions missing: insert, delete, construct...

        //Write it under zdw_list.h
        namespace zdw
        {
            template<class _Ty>
            class list //Designing a linked list, node class, iterator class
            {
            private:
                struct _node;
                typedef _node* nodeptr;
                struct _node
                {
                    nodeptr pre;
                    nodeptr next;
                    _Ty value;   //Value of Node
                };

            public:
                class const_iterator:public zdw::_Bidit<_Ty,int> //Inheritance bidirectional iterator
                {};
                class iterator:public const_iterator  
                {};
            };  
        }

This is written in namespace to prevent naming contamination and use your own naming.

4. Design your own vector

        //zdw_vector.h file design a vector 
        namespace zdw
        {
            template<class _Ty>
            class vector
            {
            public:
                class const_iterator:public zdw::_Ranrit<_Ty,int>  //random access iterators
                {};
                class iterator:public const_iterator
                {};
            };
        }


6. Design the advance d function of the iterator: the movement of the iterator

Think: Write advance again to get the iterator type? That's the point of the book: Type Extraction Trats Programming Skills

Depending on the container, the iterator moves differently:

Forward iterators (such as single-linked lists): need to move step by step.

Bidirectional iterators (such as double-linked lists): judging whether to move forward or backward

Random iterators (such as vector s arrays): step-by-step straight across

//In iterator.h 
template<class _II,class _Dist>
void _advance(_II &i,_Dist n,input_iterator_tag)//Input iterator:
{
	 while (n--) ++i;//You can only walk one by one.
}
            
template<class _II,class _Dist>
void _advance(_II &i,_Dist n,bidirectional_iterator_tag)//Bidirectional Iterator
{
	if (n >= 0)
	while (n--) ++i;  //To judge positive and negative values
	 else
	while (n++) --i;
}
            
template<class _II,class _Dist>
void _advance(_II &i,_Dist n,random_accessl_iterator_tag)//RadomAccessIterator
{
	i += n;      //Random iterators can be used directly+
}
	

But the final advance d design is a difficult point:
Design 1: Can't solve the problem, error, pass out

            template<class _II,class _Dist>
            void advance(_II &i,_Dist n) //Key and Difficult Points in the Design of this Function
            {
                //How does advance call the moving function of the _advance (_II &i, _Dist n, input_iterator_tag) bidirectional iterator?
            }
            

Design 2: Consider the iterator type as a type parameter, but there are still problems.

            template<class _II,class _Dist>        //Type plus () means that this is an object
            void advance(_II &i,_Dist n,input_iterator_tag() ) //However, how does the system know from the type of _II iterator that it is input_iterator_tag
            {
                _advance(i,n,input_iterator_tag())
            }


Design 3: // This is the focus of today's work: Type extraction does not write the results here, it needs to be analyzed step by step.


7. Write an example of type extraction:

I understand type extraction: to get the type of template, how to get it? Add an intermediate layer, or that principle, "The problem in computer can be added an intermediate layer, where the intermediate layer is the extraction extraction structure."

(1) An imperfect program: interface reuse can not be achieved:

template<class _Ty>
class SeqList
{
public:
	typedef _Ty value_type;
private:
	_Ty data[10];
	int cursize;
public:
	SeqList():cursize(0){};
	~SeqList(){};
	void push(const _Ty &x)
	{
		data[cursize++] = x;
	}
};

template<class Container>
void Append(Container &seq)
{	
	int x;
	cin>>x;
	seq.push(x);
}

int main()
{
	SeqList<int> seq;
	Append(seq);
}

The problem with this program is that if we SeqList < double > seq, then x in the Append function needs to be changed to double.

(2) Increase type extraction mechanism:

        template<class _Ty>
        class SeqList   //Let's design a sequence table.
        {
        public:
            typedef _Ty value_type;
        private: 
            _Ty data[10];
            int cursize;
        public:
            SeqList():cursize(0){};
            ~SeqList(){};
            void push(const _Ty &x)
            {
                data[cursize++] = x;
            }
        };
        
        template<class Container> //The extraction mechanism of the middle layer to get the data type in the current container
        struct traits_seq
        {
            typedef typename Container::value_type value_type;
        };
        
        template<class Container>
        void Append(Container &seq)
        {
            typename traits_seq<Container>::value_type x;
            cin>>x;
            seq.push(x);
        }
        
        int main()
        {
            SeqList<int> seq;
            Append(seq);
        }

8. Back to the extraction of advance d function in iterator

 

    template<class Iterator>
    struct itreator_traits
    {
        typedef typename  Iterator::iterator_category       iterator_category;
        typedef typename  Iterator::value_type              value_type;
        typedef typename  Iterator::difference_type         difference_type;
        typedef typename  Iterator::pointer                  pointer;
        typedef typename  Iterator::reference                reference;
    }

    
9. Writing Iterator Method: Overload ++ -- Pre-post, etc.

    
10. Solve the problem that ordinary pointer cannot be extracted

Native Type Pointer: A Random Iterator
Processing of pointers: partial specialization and complete specialization of template functions

        //Several examples of specialization:
            template<class T>
            class C{};           //No specialization
            
            template<class T>
            class C<T*>{};       //partial specialization
            
            template<class T>
            class C<const T*>{}; //partial specialization
            
            template<>
            class C<char *>{}; //complete specialization

I was impressed by what the teacher said at that time.

Template specialization is like looking for objects:

Complete specialization is just graduated young people, "I want to marry Bai Fumei, cute and lovely Dili Reba."

Part of specialization is "I want to find beautiful on the line";

No specialization is: "I marry a woman, it's OK!"
        

        //Rewriting Extraction Structures
        template<class T>
        struct iterator_traits<const T*>
        {
            iterator_traits(){};
            typedef random_access_iterator_tag iterator_category;
            typedef T                          value_type;
            typedef int                        difference_type;
            typedef T*                         pointer;
            typedef T&                          reference;
        }


11.sgi and vs
        
12. Implementation of distance function: find an example between two iterators

        template<class _II>
        typename iterator_traits<_II>::difference_type
        __distance(_II _First,_II _Last,input_iterator_tag)     //Input Iterator
        {
            typename iterator_traits<_II>::difference_type n = 0;
            for(,_First != Last;++_First,++n);
            return n;
        }
        
        template<class _RAI>
        typename iterator_traits<_RAI>::difference_type
        __distance(_RAI _First,_RAI _Last,random_access_iterator_tag) //RadomAccessIterator
        {
            return _Last - _First;
        }
    
        template<class _II>
        typename iterator_traits<_II>::difference_type
        distance(_II _First,_II _Last)      //Final distance
        {
            return __distance(_First,_Last,iterator_category(_First));
        }


11. Summary:
It is the responsibility of the iterator to design the corresponding type of iterator.
It is the responsibility of the container to design appropriate iterators.
Only the container itself knows what iterators should be designed to visit itself and perform the various behaviors (forward, backward, value, member) that iterators should have.
As for the algorithm, it can be developed independently of the container iterator, as long as the iterator is designed as the external interface.
Trats programming techniques are widely used in STL. It makes use of "embedded gender" programming skills and compiler template parameter derivation function to enhance the ability of type authentication that c++ fails to provide.
Make up for the fact that c++ is not a strongly typed language.
Understanding traits programming is the key to open STL source profiling.


12.iterator full source code:


      

 // Excerpts from SGI STL <stl_iterator.h>
        // Five types of iterators
        struct input_iterator_tag {};
        struct output_iterator_tag {};
        struct forward_iterator_tag : public input_iterator_tag {};
        struct bidirectional_iterator_tag : public forward_iterator_tag {};
        struct random_access_iterator_tag : public bidirectional_iterator_tag {};
        
        // In order to avoid any omission when writing code, the self-developed iterator is best inherited from the following std::iterator
        template <class Category, class T, class Distance = ptrdiff_t,class Pointer = T*, class Reference = T&>
        struct iterator 
        {
            typedef Category iterator_category;
            typedef T value_type;
            typedef Distance difference_type;
            typedef Pointer pointer;
            typedef Reference reference;
        };
        
        // "Juicer" traits
        template <class Iterator>
        struct iterator_traits 
        {
            typedef typename Iterator::iterator_category iterator_category;
            typedef typename Iterator::value_type value_type;
            typedef typename Iterator::difference_type difference_type;
            typedef typename Iterator::pointer pointer;
            typedef typename Iterator::reference reference;
        };
        
        // The traits partial specialization version (partial specialization) is designed for native pointer.
        template <class T>
        struct iterator_traits<T*> 
        {
            typedef random_access_iterator_tag iterator_category;
            typedef T value_type;
            typedef ptrdiff_t difference_type;
            typedef T* pointer;
            typedef T& reference;
        };

        // The traits partial specialization version (partial specialization) is designed for native pointer-to-const. Taiwan compatriots call partial specialization
        template <class T>
        struct iterator_traits<const T*> 
        {
            typedef random_access_iterator_tag iterator_category;
            typedef T value_type;
            typedef ptrdiff_t difference_type;
            typedef const T* pointer;
            typedef const T& reference;
        };
        
        // This function can easily determine the type of an iterator.
        template <class Iterator>
        inline typename iterator_traits<Iterator>::iterator_category
        iterator_category(const Iterator&) 
        {
            typedef typename iterator_traits<Iterator>::iterator_category category;
            return category();
        }
        
        // This function can easily determine the distance type of an iterator.
        template <class Iterator>
        inline typename iterator_traits<Iterator>::difference_type*  
        distance_type(const Iterator&) 
        {
            return static_cast<typename iterator_traits<Iterator>::difference_type*>(0);
        }
        
        // This function can easily determine the value type of an iterator.
        template <class Iterator>
        inline typename iterator_traits<Iterator>::value_type*
        value_type(const Iterator&) 
        {
            return static_cast<typename iterator_traits<Iterator>::value_type*>(0);
        }
        
        // Here's the whole set of distance functions
        template <class InputIterator>
        inline iterator_traits<InputIterator>::difference_type
        __distance(InputIterator first, InputIterator last,input_iterator_tag) 
        {
            iterator_traits<InputIterator>::difference_type n = 0;
            while (first != last) 
            {
                ++first; ++n;
            }
            return n;
        }
        
        template <class RandomAccessIterator>
        inline iterator_traits<RandomAccessIterator>::difference_type
        __distance(RandomAccessIterator first, RandomAccessIterator last,random_access_iterator_tag) 
        {
            return last - first;
        }
        
        template <class InputIterator>
        inline iterator_traits<InputIterator>::difference_type
        distance(InputIterator first, InputIterator last) 
        {
            typedef typename
            iterator_traits<InputIterator>::iterator_category category;
            return __distance(first, last, category());
        }
        
        // Here's the whole set of advance d functions
        template <class InputIterator, class Distance>
        inline void __advance(InputIterator& i, Distance n,input_iterator_tag) 
        {
            while (n--) ++i;
        }
        
        template <class BidirectionalIterator, class Distance>
        inline void __advance(BidirectionalIterator& i, Distance n,bidirectional_iterator_tag) 
        {
            if (n >= 0)
            while (n--) ++i;
            else
            while (n++) --i;
        }
        
        template <class RandomAccessIterator, class Distance>
        inline void __advance(RandomAccessIterator& i, Distance n,random_access_iterator_tag) 
        {
            i += n;
        }
        template <class InputIterator, class Distance>
        inline void advance(InputIterator& i, Distance n)
        {
            __advance(i, n, iterator_category(i));
        }


--------------------------------------------
 
C++ thought: simulate reality, simulate and similar! Programming is to reflect the world in the computer!
 

Topics: Programming less