今天放上一个迭代器的实现
主要解决一个问题:
在多线程的环境下,保证各个迭代的完整性。
1、多个线程在对同一个容器进行迭代,互不影响(容器自己有锁)
2、若要迭代的下一个对象被移走,迭代器要可以正确的后移,指向再下一个要迭代的对象
3、被迭代出来的当前对象被移走或释放,这个需要另外的措施保证(比如智能指针),迭代器不作处理
4、已经被迭代过的对象序列中新插入了对象,本次迭代不处理,留待下一次迭代。
迭代器用到了一个容器的基类Container,该基类向迭代器提供4个接口:
1、向该容器注册一个迭代器void Register(TIterator<T> &iter);
2、向该容器取消注册一个迭代器void UnRegister(TIterator<T> &iter);
3、迭代器开始遍历bool BeginListBy(TIterator<T> &iter);
4、迭代器获取下一个对象bool GetNextBy(TIterator<T> &iter);
Container保存一个所有在该容器上注册的迭代器列表
容器向所有子类提供一个接口:void ResetNext(T *next)
当容器remove一个对象时,需要调用该接口
检查所有注册的迭代器,判断remove的对象是否是下一个将要迭代的对象,是则将迭代器后移一个对象
关于该容器基类的实现,下篇博客做详细说明
其中关于容器提供给迭代器的:迭代器开始遍历BeginListBy 和 迭代器获取下一个对象GetNextBy 这两个接口
为什么是容器提供,而不是迭代器自己访问
这里涉及到一个锁,以及防止死锁的问题
首先,迭代器自己是不加锁的,这是使用时需要注意的,不可以将同一个迭代器对象交给不同的线程去访问
迭代一般就是一个循环,从头到尾,这个过程一般应该是在一个函数内完成
函数返回,迭代器也就应该释放掉了
其次,如果迭代器加锁,就会出现
在迭代的过程中,需要先锁迭代器,再锁容器
而在容器remove的过程中,又会出现先锁容器,再挨个锁每一个迭代器的情况
这样就有死锁
因此迭代器没有加锁
迭代器的bool BeginList()和T *GetNext()两个函数中,直接调用容器的对应两个函数来进行迭代,在容器中进行加锁,保证线程安全
关于迭代器中保存的容器指针TContainer<T> *m_pContainer
这个指针理论上也是存在线程安全的问题的
比如一个线程正在对容器进行迭代,另一个线程释放了该容器
此处迭代器暂时不考虑这种情况,默认m_pContainer是一直有效且不变的
以上问题需要考虑其他手段来保证m_pContainer对象在迭代过程中是有效的
最后迭代器类私有的new,既不希望迭代器在堆上创建对象
理由同上,迭代过程一般应该是在一个函数内完成,定义为局部变量即可,不需要new
当然并不能真正阻止在堆上创建对象,想new还是可以new出来的
这只是一个语法糖,让直接new的可以给出错误提示
下面给出代码
TIterator.h
#ifndef _TIterator_h_
#define _TIterator_h_
#include <windows.h>
#include "CList.h"
#include "tool.h"
template <class T>
class TContainer;
template <class T>
class TIterator
{
friend class TContainer<T>;
public:
TIterator();
//对象释放时,在其所注册的m_pContainer容器中取消注册
~TIterator();
//使用迭代器之前,需要将迭代器注册给需要被迭代的容器
void Register(TContainer<T>& container);
//迭代器不再使用是,将迭代器从容器中取消注册
void UnRegister();
//准备开始遍历,m_pNextPtr指向待遍历的第一个结点,返回true
//遍历环境没有准备好(没有注册给某个待遍历的容器),返回false
bool BeginList();
//返回m_pNextPtr指向的结点,同时m_pNextPtr指向下一个要遍历的结点
//遍历环境没有准备好(没有注册给某个待遍历的容器),返回空
//若遍历结束,返回空
T *GetNext();
private:
//根据链表结点地址,获取对应Iterator对象地址
//私有,仅提供给Container使用
static TIterator<T> *GetIterator(Node *pNode);
//由于一个迭代过程一般应在一个函数内完成
//因此此处私有new,即不希望Iterator在堆上创建对象
//ps: 这只是一个语法糖
// 让编译时可以给出错误提示
// 并不能真正阻止堆上创建Iterator
void* operator new(size_t size){return NULL};
//所迭代的容器
TContainer<T> *m_pContainer;
//下一个将要迭代的对象
T *m_pNextPtr;
//使Iterator可以被链表化
Node m_LinkNode;
};
#include "TIterator.hpp"
#endif
TIterator.hpp
#ifndef _TIterator_hpp_
#define _TIterator_hpp_
template <class T>
TIterator<T>::TIterator()
{
m_pContainer = NULL;
m_pNextPtr = NULL;
m_LinkNode.Node::Init();
}
template <class T>
TIterator<T>::~TIterator()
{
UnRegister();
}
template <class T>
void TIterator<T>::Register(TContainer<T>& container)
{
m_LinkNode.Node::Init();
m_pContainer = &container;
if (NULL != m_pContainer)
{
m_pContainer->Register(*this);
}
m_pNextPtr = NULL;
}
template <class T>
void TIterator<T>::UnRegister()
{
m_pNextPtr = NULL;
if (NULL != m_pContainer)
{
m_pContainer->UnRegister(*this);
m_pContainer = NULL;
}
m_LinkNode.Node::Init();
}
template <class T>
bool TIterator<T>::BeginList()
{
bool bRes = false;
if (NULL != m_pContainer)
{
bRes = m_pContainer->BeginListBy(*this);
}
return bRes;
}
template <class T>
T *TIterator<T>::GetNext()
{
T *pCurr = m_pNextPtr;
if (NULL != m_pContainer)
{
m_pContainer->GetNextBy(*this);
}
return pCurr;
}
template <class T>
TIterator<T> *TIterator<T>::GetIterator(Node *pNode)
{
TIterator<T> *pIter = ContainerOf(pNode, TIterator<T>, m_LinkNode);
return pIter;
}
#endif