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()));

}
原文地址:https://www.cnblogs.com/jinxiang1224/p/8468424.html