在经典的设计模式中,有一种迭代器模式,定义为:提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。
迭代器的主要优点如下:
访问一个聚合对象的内容而无须暴露它的内部表示。
遍历任务交由迭代器完成,这简化了聚合类。
它支持以不同方式遍历一个聚合,甚至可以自定义迭代器的子类以支持新的遍历。
增加新的聚合类和迭代器类都很方便,无须修改原有代码。
封装性良好,为遍历不同的聚合结构提供一个统一的接口。
使用过STL的童鞋就知道,迭代器是STL使用最多的技术;那么迭代器具体是怎么实现的呢?本文来讨论一下迭代器的原理和相关实现。
1. list类
首先,我们简单的模拟一个单项链表,这个链表可以往表头插入数据,并且返回表头。
1.1 ListItem
首先,我们需要一个ListItem
表示每个链表节点,这个声明如下:
namespace BH
{
template<typename T>
class ListItem;
template<typename T>
std::ostream& operator<<(std::ostream& out, ListItem& d);
template<typename T>
class ListItem
{
public:
ListItem(const T& t) : Data(t), Next(nullptr) {}
ListItem(T&& t) : Data(std::forward(t)), Next(nullptr) {}
template<typename... Types>
ListItem(Types&&... args) : Data(std::forward(args)...), Next(nullptr) {}
void setnext(ListItem* n)
{
Next = n;
}
ListItem* next()
{
return Next;
}
friend std::ostream& operator<< (std::ostream& out, ListItem& d);
private:
ListItem* Next;
T* Data;
};
template<typename T>
std::ostream& operator<<(std::ostream& out, ListItem& d)
{
out << d.Data;
return out;
}
}
首先这里构造函数:
支持普通构造。
支持移动函数。
支持参数完美转发。
友元
operator<<
,支持数据输出。
1.2 list类
这个类实现一个链表,支持简单的插入,并且返回头部节点。
namespace BH
{
template<typename T>
class list
{
public:
list() noexcept : Head(nullptr) {}
void push(const T& t)
{
ListItem* Data = new ListItem(t);
Data->setnext(Head);
Head = Data;
}
void push(T&& t)
{
ListItem* Data = new ListItem(t);
Data->setnext(Head);
Head = Data;
}
template<typename... Types>
void emplace(Types&&... args)
{
ListItem* Data = new ListItem(std::forward(args)...);
Data->setnext(Head);
Head = Data;
}
ListItem* front()
{
return Head;
}
private:
ListItem* Head;
};
}
如上,为了演示,这个类实现的很简单,只支持push,和front两个操作。
2. iterator
使用过STL都知道,iterator主要是用来遍历容器中的数据节点,那么上面这个list,我们的主要功能是能够不用在外部知道list的实现原理,使用iterator来遍历数据。
所以iterator的主要功能有:
支持 ,遍历元素。
支持*,取元素程序。
支持->,指针操作。
支持==和!=操作,比较iterator是否到了结尾。
所以这个实现可以如下:
namespace BH
{
template <typename T>
class ListIter
{
public:
using value_type = T;
using reference = T & ;
using const_referenct = const T&;
using pointer = T * ;
using const_pointor = const T*;
using size_type = size_t;
using difference_type = ptrdiff_t;
ListIter(pointer p = nullptr) : Iter(p) {}
bool operator==(const ListIter& rhs) const noexcept
{
return Iter == rhs.Iter;
}
bool operator!=(const ListIter& rhs) const noexcept
{
return Iter != rhs.Iter;
}
ListIter& operator ()
{
Iter = Iter->next();
return *this;
}
ListIter& operator (int)
{
value_type tmp = *this;
&*this;
return tmp;
}
reference operator*()
{
return *Iter;
}
pointer operator->()
{
return Iter;
}
private:
pointer Iter;
};
}
3. 使用
接下来,我们看一下这个iterator如何使用:
int main(int args, char* argv[])
{
BH::list<std::string> l;
l.push(std::string("hello"));
l.push("world");
l.push("abcd");
l.push("efg");
l.push("kmm");
BH::ListIter<BH::ListItem<std::string>> iter(l.front());
BH::ListIter<BH::ListItem<std::string>> end;
while (iter != end)
{
std::cout << *iter << std::endl;
iter;
}
return 0;
}