【c++】——string字符串对象以及vector容器的迭代器iterator实现

一、string字符串对象的迭代器iterator实现

1、基本原理

当我们给一个对象赋值了一个字符串,例如:
String str1 = “hello world”;
当我们想遍历该字符串的时候,你有想过如何遍历吗?因为其是在底层放了一组char类型的字符,我们是看不见的。

由此,我们引出了容器的迭代器类型这个概念。
具体实现如下:

String::iterator it = str1.begin();
	for (; it != str1.end(); ++it)
	{
		cout << *it << " ";
	}
	cout << endl;

其原理如下图:
在这里插入图片描述
特点:

  1. 该类型属于容器类型的嵌套类
  2. 容器内部的元素是不可见的,迭**代器可以透明的访问容器内部元素的值。**通俗来讲,不管容器底层是什么数据结构,怎么推进。例如:泛型算法参数接收的都是迭代器,他是一个全局函数是给所有函数用的,
    有一套方式能够统一的遍历所有的容器的元素
  3. 他的功能是:提供一种统一的方式,来透明的遍历容器

因此,我们需要自己实现迭代器里面的相关运算符。

2、运算符的实现

(1)给String字符串类型提供迭代器的实现
因为他是一个内嵌类型,所以写在string类的public里面。

迭代器还需要提供 * 运算符重载,访问迭代器所迭代元素的值,迭代器解引用访问的就是容器底层数据。

class iterator
	{
	public:
		iterator(char *p = nullptr):_p(p){ }
		bool operator !=(const iterator& it)
		{
			return _p != it._p;//迭代器的不相等就是底层指针的不相等
		}
		void operator++()
		{
			++_p;
		}
		char& operator*() { return *_p; }
	private:
		char* _p;
	};

(2)begin()方法
返回的是让其底层首元素的迭代器的表示

iterator begin() { return iterator(_pstr); }

(3)end()方法
返回的是容器末尾元素后继位置的迭代器的表示

iterator end() { return iterator(_pstr + length()); }

二、实现vector容器的迭代器

因为vector也是一种容器,所以我们还是可以使用上述迭代器,
(1)具体实现如下:

template <typename T>
struct Allocator
{
	T* allocate(size_t size)//只负责内存开辟
	{
		return (T*)malloc(sizeof(T) * size);
	}
	void deallocate(void* p)//只负责内存释放
	{
		free(p);
	}
	void construct(T* p, const T& val)//已经开辟好的内存上,负责对象构造
	{
		new (p) T(val);//定位new,指定内存上构造val,T(val)拷贝构造
	}
	void destroy(T* p)//只负责对象析构
	{
		p->~T();//~T()代表了T类型的析构函数
	}
};

template <typename T, typename Alloc = Allocator<T>>
class vector//向量容器
{
public:
	vector(int size = 10)//构造
	{
		//_first = new T[size];
		_first = _allocator.allocate(size);
		_last = _first;
		_end = _first + size;
	}
	~vector()//析构
	{
		//delete[]_first;
		for (T* p = _first; p != _last; ++p)
		{
			_allocator.destroy(p);//把_first指针指向的数组的有效元素析构
		}
		_allocator.deallocate(_first);//释放堆上的数组内存
		_first = _last = _end = nullptr;
	}
	vector(const vector<T>& rhs)//拷贝构造
	{
		int size = rhs._end - rhs._first;//空间大小
		//_first = new T[size];
		_first = _allocator.allocate(size);
		int len = rhs._last - rhs._first;//有效元素
		for (int i = 0; i < len; ++i)
		{
			//_first[i] = rhs._first[i];
			_allocator.construct(_first + i, rhs._first[i]);
		}
		_last = _first + len;
		_end = _first + size;
	}
	vector<T>& operator=(const vector<T>& rhs)//赋值运算符重载
	{
		if (this == &rhs)
		{
			return *this;
		}

		//delete[]_first;
		for (T* p = _first; p != _last; ++p)
		{
			_allocator.destory(p);//把_first指针指向的数组的有效元素析构
		}
		_allocator.deallocate(_first);//释放堆上的数组内存

		int size = rhs._end - rhs._first;//空间大小
		_first = _allocator.allocate(size);
		int len = rhs._last - rhs._first;//有效元素
		for (int i = 0; i < len; ++i)
		{
			_allocator.construct(_first + i, rhs._first[i]);
		}
		_last = _first + len;
		_end = _first + size;
		return *this;
	}
	void push_back(const T& val)//尾插
	{
		if (full())
		{
			expand();
		}
		//*_last++ = val;
		_allocator.construct(_last, val);//_last指针指向的内存构造一个值为val的对象
		_last++;
	}
	void pop_back()//尾删
	{
		if (empty()) return;
		//--_last;
		//不仅要把_last指针--,还需要析构删除的元素
		--_last;
		_allocator.destroy(_last);
	}
	T back()const//返回容器末尾元素值
	{
		return *(_last - 1);
	}
	bool full()const
	{
		return _last == _end;
	}
	bool empty()const
	{
		return _first == _last;
	}
	int size()const//返回容器中元素个数
	{
		return _last - _first;
	}
	T& operator[](int index)
	{
		if (index < 0 || index >= size())
		{
			throw "OutOfRangeException";
		}
		return _first[index];
	}
	//迭代器一般实现成容器的嵌套类型
	class iterator
	{
	public:
		iterator(T* ptr = nullptr)
			:_ptr(ptr) {}
		bool operator!=(const iterator& it)const
		{
			return _ptr != it._ptr;
		}
		void operator++()
		{
			_ptr++;
		}
		T& operator*()
		{
			return *_ptr;
		}
		const T& operator*()const
		{
			return *_ptr;
		}
	private:
		T* _ptr;
	};
	iterator begin()
	{
		return iterator(_first);
	}
	iterator end()
	{
		return iterator(_last);
	}
private:
	T* _first;//起始数组位置
	T* _last;//指向最后一个有效元素后继位置
	T* _end;//指向数组空间的后继位置
	Alloc _allocator;//定义容器的空间配置器对象

	void expand()//扩容
	{
		int size = _end - _first;
		//T *ptmp = new T[2*size];
		T* ptmp = _allocator.allocate(2 * size);
		for (int i = 0; i < size; ++i)
		{
			_allocator.construct(ptmp + i, _first[i]);
			//ptmp[i] = _first[i];
		}
		//delete[]_first;
		for (T* p = _first; p != _last; ++p)
		{
			_allocator.destroy(p);
		}
		_allocator.deallocate(_first);
		_first = ptmp;
		_last = _first + size;
		_end = _first + 2 * size;
	}
};

(2)迭代器遍历的三种方式

方式一:因为vector是一种数组容器,连续空间可以利用下标访问,但是这种方式遍历只针对vector有用

int size = vec.size();
	for (int i = 0; i < size; ++i)
	{
		cout << vec[i] << " ";
	}
	cout << endl;

方式二:迭代器通常访问方式

vector<int>::iterator it = vec.begin();
	for (; it != vec.end(); ++it)
	{
		cout << *it << " ";
	}
	cout << endl;

方式三:c++11中更简便的foreach的方式来遍历容器的内部元素的值.底层还是通过迭代器进行遍历的

for (int val : vec)
	{
		cout << val << " ";
	}
	cout << endl;
发布了98 篇原创文章 · 获赞 9 · 访问量 3668

猜你喜欢

转载自blog.csdn.net/qq_43412060/article/details/105136908