C++插入子浅谈

在C++里,我喜欢把or或者er结尾的类都称为什么什么子,如果iterator,叫迭代子,functor叫函数子, inserter就叫插入子了,不过也有人喜欢把iterator叫迭代器,把insertor叫插入器的。 插入子实际是一种迭代子,不过他们有更明确的用途,就是往一个容器中添加元素,所以有必要单独拿出来聊一聊。

特别说明一下,我使用的是g++4.4,所以以下的对插入子的分析都是针对g++的。本文简单分析一下,C++里的一些插入子, 主要是<stl_iterator.h>里的插入子,还有一些很有用的与数据流相当的插入子,在以后的文章里再讨论吧。

stl_iterator.h里定义了三种插入子,分别为前向插入子(back_insert_iterator),后向插入子(front_insert_iterator), 随机插入子(insert_iterator)。我们先来看看前向插入子的作用,那么其他两个也就很容易理解了。

由于是插入子也是属于迭代子,所以他们都是从模板类iterator继承而来。至于类iterator干了些什么,正如g++的风格, 一般最原始的基类是什么也不干的,只是打打酱油,只是有几条typedef语句,主要目的只是为了建立起一个概念模型起来。 以下是除去罗嗦的成员函数后剩下的部分:

template<typename _Container>
class front_insert_iterator
: public iterator<output_iterator_tag, void, void, void, void>
{
protected:
     _Container* container;
     ...
}

可见使用时需要告诉容器的类型,唯一的成员变量就是一个指向容器的指针,而且是protected类型,以方便用户扩展功能。

前向插入子的作用正如它的名字一样,为的就是在前方插入一个元素,你往里面放入一个数据,它自动帮你插入到容器的前头, 你便不必一个劲的调用容器的push_front()方法了,所以实际前向插入子的功能就是帮你调用push_front()函数, 由此就可知你的容器必需要支持push_front()方法,看看下面的源码你就该明白了:

front_insert_iterator&
operator=(typename _Container::const_reference __value)
{
     container->push_front(__value);
     return *this;
}

如果考虑效率问题,你应该知道对vector使用前向插入子绝对不是一个好主意!

好了,一个前向插入子就这么简单,至于迭代子必要的操作符,也有定义,但都不干事的,如:

front_insert_iterator&
operator*()
{ return *this; }

operator++()也是返回*thisoperator++(int)也是返回*this,所以你应该不会考虑去使用它们。

来一段示例代码瞧瞧:

front_insert_iterator<list<int> > finserter(l);
finserter = 99;//内部调用push_front()
finserter = 100;

记得写代码时加入#include <iterator>。运行后,你就会发现100放在了最前头,接着是99,finserter就像一个无底洞一样, 你只需要往里面放元素,它就能帮你放到容器的最前头。

到此,你可能觉得这个东西没有什么用处,还不如写l.push_front()来得明了,不过事实上,插入子压根就不是为这样使用而设计的, 它是为copy(),unique_copy()等算法函数而设计的。如下面的一小段代码就完成了将一个vector里的全部元素插入到另一个list容器的前头, 而不是写一个for循环,然后一个一个push_front():

int a[] = {1,2,3,4,5,6};
list<int> l;
vector<int> v(a,a+6);
front_insert_iterator<list<int> > finserter(l);
copy(v.begin(),v.end(),finserter);

当然注意代码前要加入#include <algorithm>,看到这里是不是会觉得插入子也是相当有用的咧。

搞清楚了前向插入子,那么后面插入子也是一样的道理,不过它要求容器提供对push_back()的支持, 而随机插入子就是可以方便地在容器的任意位置插入元素,而不仅仅是头部和尾部,不过它要求容器提供对insert()函数的支持。 想到插入子内部调用了什么函数,你就会自然考虑到速度问题,而不至于在vector上使用随机插入子。

//v为A,Z,
insert_iterator i(v,++v.begin());
i = 1;
i = 2;
i = 3;
//此时v为A,1,2,3,Z

为充分使用编译器的自动类型判定,<stl_iterator.h>还提供了三个函数,来直接获得某容器的插入子,如:

template<typename _Container>
inline front_insert_iterator<_Container>
front_inserter(_Container& __x)
{
     return front_insert_iterator<_Container>(__x);
}

就是直接返回一个前向插入子,这与copy()算法结合起来相当有用,这样你就省去创建创建对象的代码了。对于前面的例子你可以简写为:

copy(l.begin(), l.end(), front_inserter(l2)); 

同样对于后向插入子可以有back_inserter()来直接生成,对于随机插入子有inserter()来减少代码输入。

发表于 2010年08月30日 02:21   评论:0   阅读:1927  



回到顶部

首页 | 关于我 | 关于本站 | 站内留言 | rss
python logo   django logo   tornado logo