STL与泛型编程<十一>:Insert(安插)迭代器

介绍

用来将“赋新值操作”转换为“安插新值”操作,通过这种迭代器,算法可以执行安插(insert)操作而非覆盖(overwrite)操作。所有insert迭代器都属于output迭代器。
- Insert迭代器的功能
通常算法会将数值赋值给标的迭代器,如copy()算法

namespace std
{
    template<typename InputIterator, typename OutputIterator>
    OutputIterator copy(InputIterator from_pos, InputIterator from_end, OutputIterator to_pos)
    {
        while (from_pos != from_end)
        {
            *to_pos = *from_pos;
            ++from_pos;
            ++to_pos;
        }
        return to_pos;
    }
}

需要注意的是赋值操作会被转换为安插操作,事实上insert迭代器会调用容器的push_back(),push_front()或insert()成员函数。
- 迭代器的种类
STL与泛型编程<十一>:Insert(安插)迭代器_第1张图片
事实上它们各自调用所属容器中不同的成员函数,所以insert迭代器初始化时一定要清楚知道自己所属的容器哪一种。每一种insert迭代器都可以由一个对应的便捷函数加以生成和初始化当然,容器本身必须支持insert迭代器所调用的函数,否则insert迭代器就不可用,因此back inserters只能用在vector,deque,list,string上,front inserters只能用在deque和list上。

back inserters

声明

template <class Container> class back_insert_iterator;
/* 可知其template需要一个容器型别 */

实现如下

template <class Container>
class back_insert_iterator : public iterator<output_iterator_tag,void,void,void,void>
{
    protected:
        Container* container;

    public:
        typedef Container container_type;

        explicit back_insert_iterator (Container& x) : container(&x) {} //构造函数,需要带入容器型别为参数 

        back_insert_iterator<Container>& operator= (typename Container::const_reference value)  //赋值时调用容器的push_back()操作 
        {
            container->push_back(value); 
            return *this; 
        }

        back_insert_iterator<Container>& operator* () //什么也不做,只是返回这个对象 
        { 
            return *this; 
        }

        back_insert_iterator<Container>& operator++ () //什么也不做,只是返回这个对象 
        { 
            return *this; 
        }

        back_insert_iterator<Container> operator++ (int) //什么也不做,只是返回这个对象 
        { 
            return *this; 
        }
};

back_inserter函数声明

template <class Container>
  back_insert_iterator<Container> back_inserter (Container& x);

例子如下

#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
using namespace std;

int main(void)
{
    vector<int> col;
    //create back inserter for col
    //inconvenient way 
    back_insert_iterator<vector<int> > iter(col);
    *iter = 1;
    iter++; //此句什么也不做,有没有一样,所以不必写 
    *iter = 2;
    *iter = 3;

    copy(col.begin(),col.end(),ostream_iterator<int>(cout," "));  // 1 2 3
    cout << endl;

    //create back inserters and insert elements
    //convenient ways
    back_inserter(col) = 44;
    back_inserter(col) = 55;
    copy(col.begin(),col.end(),ostream_iterator<int>(cout," "));  // 1 2 3 44 55
    cout << endl;

    //reserve enough momory to avoid reallocation
    col.reserve(2*col.size()); //一定要在copy之前保证足够大的空间
    copy(col.begin(), col.end(), back_inserter(col));
    copy(col.begin(),col.end(),ostream_iterator<int>(cout," ")); // 1 2 3 44 55 1 2 3 44 55

    return 0;
 } 

 /* 可以看出有两种方式使用安插迭代器: 1. 使用其型别,就是使用其类。如back_insert_iterator<vector<int> > ,并加以初始化 2. 调用函数back_inserter(container);其中函数back_inserter()会产生一个back_insert_iterator迭代器 */

看看copy的源代码加强上面理解

template<class InputIterator, class OutputIterator>
OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result)
{
    while (first!=last) 
    {
        *result = *first;
        ++result; ++first;
    }
 return result;
}

front inserters

例子如下

#include <iostream>
#include <iterator>
#include <list>

using namespace std;

template<typename T>
inline void PRINT_ELEMENTS(const T& col, const char* str=" ")
{
    typename T::const_iterator pos;
    cout << str;
    for (pos=col.begin(); pos!=col.end(); ++pos)
        cout << *pos << ' ';
    cout << endl;   
}

int main(void)
{
    list<int> col;
    //create back inserter for col
    //inconvenient way 
    front_insert_iterator<list<int> > iter(col);
    *iter = 1;
    iter++;
    *iter = 2;
    iter++;
    *iter = 3;

    PRINT_ELEMENTS(col);  // 3 2 1

    //create back inserters and insert elements
    //convenient ways
    front_inserter(col) = 44;
    front_inserter(col) = 55;
    PRINT_ELEMENTS(col);  // 55 44 3 2 1

    copy(col.begin(), col.end(), front_inserter(col));
    PRINT_ELEMENTS(col); // 55 44 3 2 1 55 44 3 2 1

    return 0;
 } 
 /* 两种方式使用front 迭代器 1. 使用相应的类实例化对象,front_insert_iterator; 2. 使用函数front_inserter(container); */

General Inserters

General Inserters根据两个参数而初始化:(1)容器(2)待安插位置。迭代器内部以“待安插位置”为参数,调用成员函数insert()。函数inserter()则能更方便的产生General Inserter 并初始化;General Inserter对所有标准容器都适用,因为所有容器都有insert()成员函数,然而对关联式容器(sete和maps)而言,安插位置只是个提示,因为在这两种容器中,元素的真正位置视其实值(键值)而定,安插操作完后,general inserter获得刚刚被安插的那个元素的位置,实际上相当于调用

pos = col.insert(pos,value);
++pos;

为什么要将insert()的传回值赋值给pos呢?为了确保该迭代器的位置始终有效,如果没有这个动作,在deque,vector,string中,该general inserter本身可能会失效。因为每一安插操作可能会使指向容器的所有迭代器失效见下例子

#include <iostream>
#include <iterator>
#include <set>
#include <list>
using namespace std;

template<typename T>
inline void PRINT_ELEMENTS(const T& col, const char* str=" ")
{
    typename T::const_iterator pos;
    cout << str;
    for (pos=col.begin(); pos!=col.end(); ++pos)
        cout << *pos << ' ';
    cout << endl;   
}

int main(void)
{
    set<int> col;
    //create insert inserter for col
    //inconvenient way 
    insert_iterator<set<int> > iter(col,col.begin());
    *iter = 1;
    iter++;
    *iter = 2;
    iter++;
    *iter = 3;

    PRINT_ELEMENTS(col);  // 1 2 3

    //create insert inserters and insert elements
    //convenient ways
    inserter(col,col.end()) = 44;
    inserter(col,col.end()) = 55;
    PRINT_ELEMENTS(col);  // 1 2 3 44 55 

    list<int> col2;
    copy(col.begin(), col.end(), inserter(col2,col2.begin()));
    PRINT_ELEMENTS(col); // 1 2 3 44 55

    copy(col.begin(), col.end(), inserter(col2,++col2.begin()));
    PRINT_ELEMENTS(col2); // 1 1 2 3 44 55 2 3 44 55

    return 0;
 }
 /* 两种方式使用general迭代器 1. 使用类创建一个对象,如insert_iterator<container> 2. 使用函数inserter(container,pos) */

总结

  1. 安插迭代器共有三种:back inserters, front inserters, general inserters。
  2. 要使用它们都有两种方式:(1)使用对应的类实例化对象;(2)调用相应的函数(一般当然是这个方便)
    使用如下
// back inserters
back_insert_iterator<container> iter(container);
*iter = val //向后插
back_inserter(container) = val;  //向后插

// front inserters
front_insert_iterator<container> iter(container);
*iter = val;
front_inserter(container) = val; 

// insert inserters
insert_iterator<container> iter(container,pos);
*iter = val; //在pos后插入
inserter(container,pos); // 在pos后面插入

你可能感兴趣的:(STL与泛型编程<十一>:Insert(安插)迭代器)