适配器是标准库中的一个通用概念。容器、迭代器和函数都有适配器(C++11出现了lambda函数、function类模板、bind函数,几乎取代了函数适配器)。本质上,适配器是一种机制,能使某种事物的行为看起来像另外一种一样。栈、队列、优先队列都属于容器适配器。本文主要介绍迭代器适配器。
迭代器适配器主要有三类:反向迭代器,插入迭代器,iostream迭代器。
插入迭代器
插入迭代器有三种类型,差异在于元素插入的位置:
back_inserter( Container& c )
,在容器尾部插入,只能对有push_back()的容器使用inserter( Container& c, Container::iterator i )
,在容器内部指定迭代器前插入,只能对有insert()的容器使用。front_inserter( Container& c )
,在容器头部插入,只能对有push_front()的容器使用。
假如你不能确定容器的大小,使用这三种迭代器,可以保证了不会造成越界的情况。
vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
fill_n(inserter(v, v.begin() + 1), 3, -2); // v:1 -2 -2 -2 2 3 4 5 6 7 8 9 10
vector<int> v2;
copy(v.begin(),v.end(),back_inserter(v2)); // v2:1 -2 -2 -2 2 3 4 5 6 7 8 9 10
deque<int> d;
copy(v.begin(),v.end(),front_inserter(d)); //逆序插入 d:10 9 8 7 6 5 4 3 2 -2 -2 -2 1
原理分析
每一个insert iterators 内部都维护有一个容器(必须由用户指定);容器当然有自己的迭代器,于是,当客户端对insert iterators做赋值(assign)操作时,就在insert iterators中被转为对该容器的选代器做插入操作,也就是说,在insert iterators的operator=操作符中调用底层容器的push_front()或push_back()或insert()操作函数。至于其它的迭代器惯常行为如operator++
,operator++(int)
,operator*
都被关闭功能,更没有提供operator--(int)
或operator--
或operator->
等功能。换句话说,insert iterators的前进、后退、取值、成员取用等操作都是没有意义的,甚至是不允许的。
下面是back_inserter源码:
template <class Container>
class back_insert_iterator
{
protected:
Container* container;
public:
typedef output_iterator_tag iterator_category;
typedef void value_type;
typedef void difference_type;
typedef void pointer;
typedef void reference;
explicit back_insert_iterator(Container& x) : container(&x) {}
// 只有提供了push_back()操作的容器才能使用back_insert_iterator
back_insert_iterator<Container>&
operator=(const typename Container::value_type& value)
{
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; }
};
反向迭代器
反向迭代器就是将迭代器的移动行为倒转。如果STL算法接受的不是一般正常的迭代器,而是这种逆向迭代器,它就会以从尾到头的方向来处理序列中的元素。例如:
//将所有元素逆向拷贝到ite所指位置上
//rbegin()和rend()返回的就是反向迭代器
copy(id.rbegin(),id.rend(),ite);
id.rbegin().base()
返回反向迭代器对应的正向迭代器id.end()
。
rbegin()
虽然对应于原迭代器的end()
,但是逆向迭代器的operator* 被重载为将"对应的正向迭代器后退一格而后取值",因此*id.rbegin()
返回容器尾部元素值。这么做是为了配合迭代器区间左闭右开的习惯,使其不用额外修改就能搭配原有的STL函数。
实线表示取值*时对应的迭代器,虚线表示实际对应的迭代器。
template <class Iterator>
class reverse_iterator
{
protected:
Iterator current;
public:
typedef typename iterator_traits<Iterator>::iterator_category
iterator_category;
typedef typename iterator_traits<Iterator>::value_type
value_type;
typedef typename iterator_traits<Iterator>::difference_type
difference_type;
typedef typename iterator_traits<Iterator>::pointer
pointer;
typedef typename iterator_traits<Iterator>::reference
reference;
typedef Iterator iterator_type;
typedef reverse_iterator<Iterator> self;
public:
reverse_iterator() {}
explicit reverse_iterator(iterator_type x) : current(x) {}
reverse_iterator(const self& x) : current(x.current) {}
#ifdef __STL_MEMBER_TEMPLATES
template <class Iter>
reverse_iterator(const reverse_iterator<Iter>& x) : current(x.current) {}
#endif /* __STL_MEMBER_TEMPLATES */
iterator_type base() const { return current; }
reference operator*() const {
Iterator tmp = current;
return *--tmp;
}
#ifndef __SGI_STL_NO_ARROW_OPERATOR
pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */
self& operator++() {
--current;
return *this;
}
self operator++(int) {
self tmp = *this;
--current;
return tmp;
}
self& operator--() {
++current;
return *this;
}
self operator--(int) {
self tmp = *this;
++current;
return tmp;
}
self operator+(difference_type n) const {
return self(current - n);
}
self& operator+=(difference_type n) {
current -= n;
return *this;
}
self operator-(difference_type n) const {
return self(current + n);
}
self& operator-=(difference_type n) {
current += n;
return *this;
}
reference operator[](difference_type n) const { return *(*this + n); }
};
iostream迭代器
- istream_iterator(),输入迭代器,可以对istream对象进行操作
- ostream_iterator(),输出迭代器,可以对ostream对象进行操作
所谓iostream迭代器,可以将迭代器绑定到一个stream(数据流)对象身上。绑定istream对象(例如cin)者,称为istream_iterator,拥有输入能力;绑定到ostream对象(例如cout)者,称为ostream_iterator,拥有输出能力。
cout<<accumulate(istream_iterator<int>(cin),istream_iterator<int>(),0);//输出从标准输入读取的值得和
vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
ostream_iterator<int> out_iter(cout," ");//第一位参数为绑定输出流;第二位参数为输出分隔符,默认为空字符串
copy(v.begin(),v.end(),out_iter);//标准输出1 2 3 4 5 6 7 8 9 10
数组输出:
copy(arr.begin(), arr.end(), ostream_iterator<int>(cout," "));
原理分析
- istream迭代器
所谓绑定一个istream object,其实就是在istream_iterator内部维护一个istream member,客户端对于这个迭代器所做的operator++操作,会被导引调用迭代器内部所含的那个istream member的输入操作(operator>>)。这个迭代器是个Input iterator,不具备operator- -。如下是可读性比较强的一种源码版本。
template <class T, class Distance = ptrdiff_t>
class istream_iterator
{
friend bool
operator== __STL_NULL_TMPL_ARGS (const istream_iterator<T, Distance>& x,
const istream_iterator<T, Distance>& y);
protected:
istream* stream;
T value;
bool end_marker;//是否继续输入,结束为false,继续为true
void read() {//读取输入流
end_marker = (*stream) ? true : false;
if (end_marker) *stream >> value;
end_marker = (*stream) ? true : false;
}
public:
typedef input_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef const T* pointer;
typedef const T& reference;
istream_iterator() : stream(&cin), end_marker(false) {}//使用默认构造时,读取标记关闭,不再读取,相当于eof
istream_iterator(istream& s) : stream(&s) { read(); }//绑定时已开始读取
reference operator*() const { return value; } //返回输入的数据
#ifndef __SGI_STL_NO_ARROW_OPERATOR
pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */
istream_iterator<T, Distance>& operator++() {
read();
return *this;
}
istream_iterator<T, Distance> operator++(int) {
istream_iterator<T, Distance> tmp = *this;
read();
return tmp;
}
};
- ostream迭代器
所谓绑定一个ostream object,就是在其内部维护一个ostream member,客户端对于这个迭代器所做的 operator=操作,会被导引调用对应的(迭代器内部所含的)那个ostream member的输出操作(operator<<).这个迭代器是个Oufputterator.下面的源代码和注释说明了一切。
至于ostream iterator,所谓绑定一个ostream object,就是在其内部维护一个ostream member,客户端对于这个迭代器所做的 operator=操作,会被导引调用对应的(迭代器内部所含的)那个ostream member的输出操作(operator<<)。这个迭代器是个Output iterator。
template <class T>
class ostream_iterator
{
protected:
ostream* stream;
const char* string;
public:
typedef output_iterator_tag iterator_category;
typedef void value_type;
typedef void difference_type;
typedef void pointer;
typedef void reference;
ostream_iterator(ostream& s) : stream(&s), string(0) {}
ostream_iterator(ostream& s, const char* c) : stream(&s), string(c) {}
ostream_iterator<T>& operator=(const T& value) {
*stream << value;
if (string) *stream << string;
return *this;
}
ostream_iterator<T>& operator*() { return *this; }
ostream_iterator<T>& operator++() { return *this; }
ostream_iterator<T>& operator++(int) { return *this; }
};
参考:
《STL源码剖析》