迭代器(iterators)概念与traits编程技法
迭代器(iterators)是一种抽象的设计概念,其中iterator模式定义如下:提供一种方法,使之能够依序巡访某个聚合物(容器)所含的各个元素,而又无需暴露该聚合物的内部表述方式。
3.1 迭代器设计思想——STL关键所在
- 不论是泛型思维或STL的实际运用,迭代器(iterators)都扮演着重要的角色。
- STL的中心思想在于:将数据容器(containers)和算法(algorithms)分开,彼此
独立设计,最后再以帖胶着剂将它们撮合在起。 - 容器和算法的泛型化,从技术角度来看并不困难,C++的class templates和function templates可分别达成目标。如何设计出两者之间的良好胶着剂,才是大难题。
以下是容器、算法、迭代器(iterator,扮演粘胶角色)的合作展示。以算法find()为例,它接受两个迭代器和个“搜寻目标":
//来自SGI <stl_algo.h>
template <class InputIterator,class T>
InputIterator find(InputIterator first,InputIterator last,const T& value){
while(first != last && *fist != value)
++first;
return first;
}
只要给予不同的迭代器,find()便能够对不同的容器进行查找操作:
#include <iostream>
#include<vector>
#include<list>
#include<deque>
#include<algorithm>
using namespace std;
int main()
{
const int arraySize = 7;
int ia[arraySize] = {
0,1,2,3,4,5,6};
vector<int> ivect(ia,ia+arraySize);
list<int> ilist(ia,ia+arraySize);
deque<int> ideque(ia,ia+arraySize);
vector<int>::iterator it1 = find(ivect.begin(),ivect.end(),4);
if(it1 == ivect.end())
cout<<"4 not found."<<endl;
else
cout<<"4 found."<<*it1<<endl;
list<int>::iterator it2 = find(ilist.begin(),ilist.end(),6);
if(it2 == ilist.end())
cout<<"6 not found."<<endl;
else
cout<<"6 found"<<*it2<<endl;
deque<int>::iterator it3=find(ideque.begin(),ideque.end(),8);
if(it3 == ideque.end())
cout<<"8 not found."<<endl;
else
cout<<"8 found."<<*it3<<endl;
}
3.2 迭代器(iterators)是一种smart pointe
- 迭代器是一种行为类似指针的对象,而指针的各种行为中最常见也最重要的便是内容提领(dereference)和成员访问(member access) , 因此, 迭代器最重要的编程工作就是对operator*和operator->进行重载(overloading)工作。
- C++标准程序库有一个auto_ptr这是一个用来包装原生指针(native pointer)的对象, 声名狼藉的内存漏洞(memory leak)问题可藉此获得解决。
auto_ptr用法如下, 和原生指针一模一样:
void func()
{
auto_ptr<string> ps(new string("jjhou"));
cout<<*ps<<endl;//输出:jjhou
cout<<ps->size()<<endl;//输出:5
//离开前不需 delete, auto_ptr 会自动释放内存
}
函数第一行的意思是, 以算式new动态配置一个初值为 ''jjhou" 的string对象,并将所得结果(一个原生指针)作为auto_ptr对象的初值。注意, auto_ptr角括号内放的是 “原生指针所指对象” 的型别, 而不是原生指针的型别。
auto_ptr 的源代码在头文件中,auto_ptr的行为如下:
template<class T>
class auto_ptr {
public:
explicit auto_ptr(T *p = 0): pointee(p) {
}
template<class U>
auto_ptr(auto_ptr<U>& rhs): pointee(rhs.release()) {
}
_auto_ptr() {
delete pointee; }
template<class U>
auto_ptr<T>& operator=(auto_ptr<U>& rhs) {
if(this !=&rhs) reset(rhs.release());
return *this;
}
T& operator* () const {
return *pointee; }
T* operator->()const {
return pointee; }
T* get() const{
return pointee;}
//...
private:
T *pointee;
};
有了模仿对象,设计list迭代器,list节点的结构如下:
template <typename T>
class List
{
void insert_front(T value);
void insert_end(T value);
void display(std::operator &os = std::cout)const;
//...
private:
ListItem<T>* _end;
ListItem<T>* _front;
long _size;
};
template<typename T>
class LisItem
{
public:
T value()const {
return _value;}
ListItem* next() const {
return _next;}
//...
private:
T _value;
ListItem* _next;//单向链表
};
- 如何将这个List套用到先前所说的find()呢?我们需要为它设计一个行为类似指针的外衣,也就是个迭代器。
- 当我们提领这一迭代器时,传回的应该是个ListItem对象;
- 为了让该迭代器适用于任何型态的节点,而不只限于Listrtem, 我们可以将它设计为一个class template:
template <class Item> // Item可以是单向链表节点或双向链表节点。
struct ListIter
{
Item* ptr;
ListIter(Item* p = 0):ptr(p){
}//默认构造
//不必实现copy ctor, 因为编译器提供的缺省行为己足够
//不必实现operator=, 因为编译器提供的缺省行为己足够
Item& operator* () const{
return *ptr; }
Item* operator->() const {
return ptr; }
//(1) pre-increment operator
Listiter& operator++()
{
ptr = ptr->next ();
return *this;
}
//(2) post-increment operator
Listiter operator++(int)
{
Listiter tmp = *this;
++*this;
return tmp;
}
bool operator==(const Listiter& i) const
{
return ptr == i.ptr;
}
bool operator !=(const ListIter& i) const
{
return ptr != i.ptr;
}
};
现在我们可以将List和find()藉由Listiter粘合起来:
void main()
{