自己的底层代码库(十)——迭代器

今天放上一个迭代器的实现


主要解决一个问题:

在多线程的环境下,保证各个迭代的完整性。

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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值