C++STL insert_iterator(插入迭代器)、ostream迭代器的重载

今天看侯老的STL源码剖析看到insert_iterator这一块突然发现一个细节
Alt
上图用inserter适配器来当copy函数的第三参数,我们知道copy的第三参数需要是一个迭代器,那么我们很自然的能够想到inserter应该是返回的一个insert_iterator类型的对象。
如图,确实是这样的,返回的是一个insert_iterator类型临时对象。
然后我们看图上copy的源码,发现对于一般的迭代器来说是没有任何问题的,将一个容器的内容拷贝到另一个容器中。但是我们知道insert顾名思义是需要插入元素到容器中,那么传入的第三参数insert_iterator是怎么样在已经写死的copy函数里边插入元素的呢。
关键在这一行

*result=*first

对于一般的容器来说,对迭代器解引用是调用operator返回其中的元素,如list链表就是返回结构体的data元素return (_Ptr->_Myval); 数组vector就是返回return (_Reft(*this));总之可以理解为返回迭代器“指向”的那个元素
当然对于一般的迭代器没什么好说的,将右值赋给左值,然后更新迭代器的位置准备下次赋值就行了。
但是对于迭代器来说,一般我们的思想就是根据运算符优先级来判断运算顺序:先对他调用解引用
使其返回一个它指向的对象嘛,注意我这里的对象打了引号,具体原因后面再讲,然后再调用assign=运算符,完成赋值操作。
但是,对于insert_iterator迭代器来说,对他调用*会产生什么结果呢,源码如下:

_NODISCARD insert_iterator& operator*()
		{	// pretend to return designated value
		return (*this);
		}

呀! 我们发现对insert_iterator进行解引用的时候,它返回的就是它本身,真是奇怪。源码也写道pretend to return designated value,假装返回指定值,原来如此,运算符*实际上对insert_iterator没有做任何的事情,因此忽略它对我们的程序没有任何影响
然后我们对它进行=重载,源码如下:

insert_iterator& operator=(const typename _Container::value_type& _Val)
		{	// insert into container and increment stored iterator
		iter = container->insert(iter, _Val);
		++iter;
		return (*this);
		}

	insert_iterator& operator=(typename _Container::value_type&& _Val)
		{	// push value into container
		iter = container->insert(iter, _STD move(_Val));
		++iter;
		return (*this);
		}

分别对应于const变量和非const变量进行重载。我们可以看到,其实在assign运算符重载的时候,iter指针是更新了自己位置的,每次插入一个元素,指针就++一次指向插入元素的下一个位置。
那么现在就很清楚了,当调用insert(foo,it),对下面这样的赋值语句

*result=*first//result是插入迭代器

其效果与下面代码是一样的

it = foo.insert(it,*first)
++it;

那么,既然*没有作用,*result=*first可以重写成result=*first吗,当然是可以的,忽略它们对程序没有任何影响,但是C++ Primer对这一细节作出了如下的解释:
推荐第一种形式,这样使用与其他迭代器额使用保持一致,如果想将此循环改为操作其他迭代器类型,修改起来非常容易,而且,对于读者来说,此循环的行为也更为清晰。

另外,我在源码中还发现了插入迭代器的++、&等操作符重载,和*一样,这些运算符都是存在的,但不对迭代器对象自身做出任何事情,每个运算符都返回对象自身。
到此 ,我们也能理解为什么++result++iter不会对指针连续自增两次了,因为**++result根本没对foo的指针it做任何的操作**,这样做的目的只是为了和一般迭代器的用法一致,保持写程序的这种习惯而已。
源码如下:

_NODISCARD insert_iterator& operator*()
		{	// pretend to return designated value
		return (*this);
		}

	insert_iterator& operator++()
		{	// pretend to preincrement
		return (*this);
		}

	insert_iterator& operator++(int)
		{	// pretend to postincrement
		return (*this);
		}

还有一点,insert_iterator不支持–运算符重载,可以看出它是单向迭代器。另外ostream_iterator和insert迭代器一样,*、++等运算符都存在,也可以使用,但是都不对对象做任何操作,只是返回对象自身,这样做的原因就是为了迎合其他迭代器的口味,与迭代器这个大家庭的用法一致。方便阅读和修改。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值