《深入实践C++模板编程》之五——容器与迭代器

Posted predator-wang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《深入实践C++模板编程》之五——容器与迭代器相关的知识,希望对你有一定的参考价值。

1、容器的定义
容器:专门用于某种形式组织及存储数据的类称为“容器”。
 
2、容器与迭代器
迭代器:封装了对容器虚拟数据序列的操作并按约定提供统一界面以遍历容器内容的代理类即为迭代器。
 
举例理解:
template<typename T> class list;

template<typename T>
struct list_node

    typedef T value_type;
    typedef T& reference_type;
    typedef const T const_reference_type;

    T value;
    list_node *prev;
    list_node *next;

    list_node(T const &value, list_node *prev, list_node *next) :
        value(value), prev(prev), next(next)
;

template<typename N> 
class list_iterator

    N *pos;
    template<typename T> friend class list;

public:
    typedef typename N::value_type value_type;
    typedef typename N::reference_type reference_type;
    typedef typename N::const_reference_type const_reference_type;
    typedef list_iterator<N> self_type;

    list_iterator() :pos(0)
    list_iterator(N *pos) :pos(pos)

    bool operator != (self_type const &right) const
        return pos != right.pos;
    

    bool operator == (self_type const &right) const
        return pos != right.pos;
    

    self_type& operator++()
        if (pos) pos = pos->next;
        return *this;
    

    reference_type operator * () throw (std::runtime_error)
        if (pos) return pos->value;
        else throw (std::runtime_error("null iterator!\n"));
    
;

template<typename T>
class list

    typedef list_node<T> node_type;
    node_type *head;

public:
    typedef T value_type;
    typedef list_iterator<node_type> iterator;

    list() :head()
    ~list()
        while (head)
        
            node_type *n = head;
            head = head->next;
            delete n;
        
    

    void push_front(T const &v)
    
        head = new node_type(v, 0, head);
        if (head->next)
        
            head->next->prev = head;
        
    

    void pop_front(T const &v)
    
        if (head)
        
            node_type *n = head;
            head = head->next;
            head->prev = 0;
            delete n;
        
    

    void insert(iterator it, T const &v)
    
        node_type *n = it.pos;
        if (n)
        
            node_type *new_node = new node_type(v, n, n->next);
            new_node->next->prev = new_node;
            n->next = new_node;
        
    

    void erase(iterator &it)
    
        node_type *n = it.pos;
        ++it;
        if (n)
        
            if (n->next)
            
                n->next->prev = n->prev;
            
            if (n->prev)
            
                n->prev->next = n->next;
            
            if (head == n)
            
                head = n->next;
            
            delete n;
        
    

    bool is_empty() const  return head == 0; 
    iterator begin() return iterator(head); 
    iterator end() return iterator(); 
;
针对树形结构节点类型的迭代器:
template<typename T>
struct tree_node

    typedef T value_type;
    typedef T& reference_type;
    typedef const T& const_reference_type;

    T value;
    tree_node *parent;
    tree_node *left;
    tree_node *right;

    tree_node(T const &value,
        tree_node *parent,
        tree_node *left, 
        tree_node *right):
        value(value),
            parent(parent),
            left(left),
            right(right)

        ~tree_node()
        
            if (left) delete left;
            if (right) delete right;
        
;

template<typename N>
class tree_iterator

    const N *pos;
public:
    typedef typename N::value_type value_type;
    typedef typename N::const_reference_type const_reference_type;
    typedef tree_iterator<N> self_type;

    tree_iterator() :pos(0)
    tree_iterator(const N *pos) :pos(pos)

    bool operator == (self_type const &right) const
        return pos == right.pos;
    

    self_type& operator ++ ()
        if (pos)
            if (pos->right)
                pos = pos->right;
                while (pos->left)
                
                    pos = pos->left;
                
            
            else
            
                while (pos->parent && (pos->parent->right == pos))
                
                    pos = pos->parent;
                
                pos = pos->parent;
            
        
        return *this;
    

    const_reference_type operator * () const throw(std::runtime_error)
    
        if (pos)
        
            return pos->value;
        
        else
        
            throw std::runtime_error("Null iterator!\n");
        
    
;

template<typename T>
class set

    typedef tree_node<T> node_type;
    node_type *root;
public:
    typedef T value_type;
    typedef tree_iterator<node_type> const_iterator;

    set() :root()
    ~set() if (root) delete root; 

    bool insert(T const &v)
    
        node_type **n = &root;
        node_type *p = 0;
        while (*n)
        
            if (v == (*n)->value)
            
                return false;
            
            else
            
                p = *n;
                n = v < (*n)->value ? &((*n)->left) : &((*n)->right);
            
        
        *n = new node_type(v, p, 0, 0);
        return true;
    

    bool has(T const &v)
    
        node_type *n = root;
        while (n)
        
            if (v == n->value)
                return true;
            n = v < n->value ? n->left : n->right;
        
        return false;
    

    bool is_empty() const  return root == 0; 

    const_iterator begin() const
        node_type *n = root;
        while (n->left) n = n->left;
        return const_iterator(n);
    

    const_iterator end() const  return const_iterator(); 
;
尽管容器内部的数据结构类型不同(set是一个树形结构,而list是链表结构),但是提供给用户的操作界面iterator的所有操作都是相同的,所以底层数据结构对用户来说是透明的。
这也算是一种设计思路。
 
3、迭代器和算法
利用迭代器求和:
template<typename C>
typename C::value_type
sum(C &c)

    typedef typename C::value_type value_type;
    typedef typename C::iterator iterator;
    value_type sum(0);

    for (iterator i = c.begin(); i != c.end(); ++i)
    
        sum += *i;
    
    return sum;
不足1:只能求所有元素之和,不能求部分元素之和。可以将一个迭代器改为两个迭代器来弥补这里的不足。
template<typename I>
typename I::value_type
sum(I begin, I end)

    typedef typename I::value_type value_type;

    value_type sum(0);
    for (; begin != end; ++begin)
    
        sum += *begin;
    
    return sum;
不足2:要兼容最原始的容器——数组。
这里的I都是某种类型的迭代器,你可以通过I::value_type获取迭代器所指的对象的类型。但是数组的指针是一个普通的指针,是没有value_type成员的。借助另外一个类模板及模板特例功能来统一描述迭代器指针的特性。
 
再进行一层封装,使得普通的指针也有了value_type:
template<typename I>
struct iterator_traits

    typedef typename I::value_type value_type;
;

template<typename P>
struct iterator_traits<P*>

    typedef P value_type;
;
改进后:
template<typename I>
typename iterator_traits<I>::value_type
sum(I begin, I end)

    typedef typename iterator_traits<I>::value_type value_type;

    value_type sum(0);
    for (; begin != end; ++begin)
    
        sum += *begin;
    
    return sum;
4、迭代器的陷阱
a、容器中通常有迭代器为参数对指定位置进行操作的成员函数,调用此类函数有个隐含要求,即迭代器所指数据来自该容器,否则后果无法预测。
b、由于迭代器独立于容器之外,用户可以一次性生成多个迭代器对容器内数据进行操作。这样就会产生冲突。

 

以上是关于《深入实践C++模板编程》之五——容器与迭代器的主要内容,如果未能解决你的问题,请参考以下文章

深入理解C++迭代器:让你的C++代码更加灵活

C++ STL与迭代器

《深入实践C++模板编程》之六——标准库中的容器

C++中的迭代器

C++中容器的迭代器用法与实战

迭代器与萃取技术