zoukankan      html  css  js  c++  java
  • Insert Iterators(安插型迭代器)

    前言

          C++标准库中提供了数个预先定义的特殊迭代器,也就是所谓的迭代器配接器(iterator adapter),它不仅起到辅助作用,还能赋予整个迭代器更加强大的能力。就像任何东西其行为像函数,我们就可以认为是函数,这样特殊的函数我们称为仿函数;类似的,任何东西,只要其行为类似迭代器,它就是一个迭代器。因此我们可以撰写一些类别,使其具备迭代器接口,但有着各不相同的行为。这些特殊的迭代器就是我们说的迭代器配接器,STL中主要有三种迭代器配接器:

               1.Insert Iterators (安插型迭代器)

               2.Stream Iterators(流迭代器)

               3.Reverse Iterators(逆向迭代器)

    本文主要探讨安插型迭代器的类别和使用,先看一个例子。

    例子一

    int _tmain(int argc, _TCHAR* argv[])
    {
    	list<int> ilist;
    	vector<int> iVec;//ivec初始未指定大小,默认是0
    
    	for (int i = 0; i < 6; i++)
    	{
    		ilist.push_back(i);
    	}
    
    	//iVec.resize(ilist.size()); 方式一
    	//copy(ilist.begin(), ilist.end(), back_inserter(iVec));//方式二:采用迭代器 back_inserter
    	copy(ilist.begin(), ilist.end(), iVec.begin());//目标空间不足,运行奔溃
    	
    	return 0;
    }
    结论:

                 1、执行copy算法时,必须确保目标空间有足够的大小,但ivec的空间大小为0,将源空间的值会逐一的赋值到目标空间ivec中,由于执行涂写操作(赋值),导致程序执行异常。

                 2、采用方式一、二都能确保足够的目标空间,方式二就是此次讨论的安插型迭代器,Insert Iterators会促使目标空间按需要增长

    Insert迭代器

    Insert迭代器,也称为inserts,用来将“赋值新增”操作行为转换为“安插新值”操作,通过这种迭代器,算法可以执行安插(insert)操作而非覆盖行为至于插入位置是在容器的前面或最后,或者某个特定的位置,须视三种不同的insert Iterator 而定。所有的Insert迭代器都属于Output迭代器类型。

    通常算法会将数值赋值给标的迭代器。例如copy()算法:

    namespace std 
    {
    	template <class InputIterator, class OutputIterator>
    	OutputIterator copy(InputIterator from_begin,	//beginning of source
    						InputIterator from_end,		//end of source
    						OutputIterator to_pos)		//beginning or dest
    	{
    		while (from_begin != from_end)
    		{
    			*to_pos = *from_begin;	//copy value
    			++from_begin;			//increment interator
    			++to_pos;
    		}
    
    		return to_pos;
    	}
    }
    我们需要注意的是:*to_pos = values; Insert 迭代器内部会重载“=”,从而将赋值动作转为安插操作,具体见源码。这里分为两个操作:

    1、operator* 是一个无实际动作的动作(no-op),只是简单的传回*this。因此对insert迭代器而言,*pos 与pos其实是等价。

    2、赋值操作被转换为安插操作。不同的insert迭代器会调用容器内部的push_back(),push_front(),insert()成员函数。

    如上描述,对于一个insert迭代器,我们写为 pos = value或者*pos=value。但从概念上理解,使用“*pos = value”更为正确, 如图表1是insert迭代器所有的操作函数。

    Insert Iterator 分类

    1. Back Inserters(安插于容器最尾端)

    Back Inserters的内部调用push_back(),在容器的尾端插入元素,也只有能提供push_back()的成员函数的容器才能使用back insert迭代器,STL中有vector、deque、list。


    2. Front  Inserters(安插于容器最前端)

     front inserts的内部调用push_front(),在容器的最前端插入元素,在STL 容器中能使用该迭代器的容器有deque、list;


    3.General Inserters(一般性安插器)

    对于这种安插型迭代器,简称inserts,该insers内部调用的成员函数是inserter(),并新值和新位置作为参数,所有的STL容器都提供inserter()成员函数,也是唯一能够作用于关联式容器的迭代器。我们知道对于关联式容器进行插入时,不能指定其位置,它的位置有键值决定,在关联式容器中我们给出的位置信息仅仅是一个提示作用,帮助它从什么地方开始搜寻正确的安插位置。

    这里通过分析back_insert_iterator类为例讨论其功能,Back inserter重载operator=完成后端插入,其他类型的迭代器的插入也是通过重载operator=完成,只是调用的函数不同罢了。back_insert_iterator类源码代码如下:

    template<class _Container>
    class back_insert_iterator: public _Outit
    {	// wrap pushes to back of container as output iterator
    public:
    	typedef _Container container_type;
    	typedef typename _Container::reference reference;
    
    	typedef _Range_checked_iterator_tag _Checked_iterator_category;
    
    	explicit back_insert_iterator(_Container& _Cont)
    		: container(&_Cont)
    		{	// construct with container
    		}
    
    	back_insert_iterator<_Container>& operator=(
    		typename _Container::const_reference _Val)
    		{	
    			// push value into container
    			container->push_back(_Val);
    			return (*this);
    		}
    
    	back_insert_iterator<_Container>& operator*()
    		{	
    			// pretend to return designated value
    			return (*this);
    		}
    
    	back_insert_iterator<_Container>& operator++()
    		{	
    			// pretend to preincrement
    			return (*this);
    		}
    
    	back_insert_iterator<_Container> operator++(int)
    		{	
    			// pretend to postincrement
    			return (*this);
    		}
    protected:
    	_Container *container;	// pointer to container
    };

    例子二

    /****************************************************************
    *函数名称:BackInsert
    *功    能:back insertor功能应用
    *作    者:Jin
    *日    期:2016年6月2日
    ****************************************************************/
    void BackInsert()
    {
    	vector<int> nVector;//creat empty vector
    	for (int i = 1;i <= 3;i++)
    	{
    		nVector.push_back(i * 10);
    	}
    	//creat back_insert iterator
    	back_insert_iterator<vector<int> > iter(nVector);
    
    	*iter = 1;	//push_back(1)
    	iter++;		//假装递增,无实际意义
    
    	iter = 2;	//等同于 *iter = 2;push_back(2)
    	*iter = 3;	//push_back(3)
    
    	//output: 10 20 30 1 2 3 
    	PrintElements(nVector,"vector list:");
    
    	//create back inserter and insert element
    	//convenient way
    	back_inserter(nVector) = 44;
    	back_inserter(nVector) = 54;
    
    	deque<int> nDeque;//creat empty deque
    	copy(nVector.begin(), nVector.end(),back_inserter(nDeque));
    	//Output: 10 20 30 1 2 3 44 54
    	PrintElements(nDeque, "queue list:");
    }

    例子三

    void InsertIterator()
    {
    	list <int> iList;
    	for (int i = 1; i < 10; ++i)
    	{
    		iList.push_back(i);
    	}
    
    	vector<int> iVector;
    	//back_inserter 插入末尾
    	copy(iList.begin(), iList.end(), back_inserter(iVector));
    
    	deque<int> iDeque;
    	//front_inserter 插入首部
    	copy(iList.begin(), iList.end(), front_inserter(iDeque));
    
    	set<int> iSet;
    	//only work for associative collections
    	copy(iList.begin(), iList.end(), inserter(iSet, iSet.begin()));
    
    }
  • 相关阅读:
    ADF_ADF基本概要(汇总)
    DBA_实践指南系列11_Oracle Erp R12性能调优基础(案例)
    DBA_实践指南系列10_Oracle Erp R12诊断功能Diagnostic(案例)
    DBA_实践指南系列9_Oracle Erp R12应用补丁AutoPatch/AutoControl/AutoConfig(案例)
    DBA_实践指南系列8_Oracle Erp R12数据维护模式Adadmin(案例)
    DBA_实践指南系列7_Oracle Erp R12监控OAM(案例)
    DBA_实践指南系列6_Oracle Erp R12工作流通知邮件配置Email(案例)
    DBA_实践指南系列5_Oracle Erp R12日常运维和管理(案例)
    DBA_实践指南系列4_Oracle Erp R12系统备份和恢复Backup(案例)
    DBA_实践指南系列3_Oracle Erp R12系统克隆Clone(案例)
  • 原文地址:https://www.cnblogs.com/jinxiang1224/p/8468424.html
Copyright © 2011-2022 走看看