C++:关于模拟实现vector和list中迭代器模块的理解

文章目录

本篇是关于vectorlist的模拟实现中,关于迭代器模块的更进一步理解,以及在前文的基础上增加对于反向迭代器的实现和库函数的对比等

本篇是写于前面模拟实现的一段时间后,重新回头看迭代器的实现,尤其是在模板角度对list中迭代器封装的部分进行解析,希望可以对迭代器的封装实现有更深层次的理解,同时将与库内的实现做对比进行优化处理

list和vector的迭代器对比

listvector的迭代器实现是不一样的,在vector中的迭代器就是一个原生指针,因此在实现的时候也就是用的原生指针即可,但是对于list来说不能这样,list的迭代器中例如++--这样的操作,是不能和vector中的原生指针一样直接去实现的,而是需要用next或者是prior来模拟这个过程,还有例如*和->这样的访问数据的模式,因此在list的迭代器实现中是使用了封装来进行实现的

STL中有六大组件,其中迭代器算其中一个,那么也就意味着迭代器具有通用的功能,例如下面的代码,在使用构造函数时可以使用迭代器进行构造,而这个构造的过程使用的迭代器对于各种容器来说都是通用的:

cpp 复制代码
#include <iostream>
#include <vector>
#include <list>
using namespace std;

int main()
{
	vector<int> v1{ 1,2,3,4,5,3,2,2 };
	vector<int> v2(v1.begin(), v1.end());
	list<int> l1(v1.begin(), v1.end());
	return 0;
}

那么就意味着,在实现迭代器的过程中也是就可以根据迭代器来进行不同容器间的构造

list的实现过程

首先,在list的实现过程中要有下面几个部分组成:list中包含的节点,list的迭代器访问,list的节点之间的关系

那么首先就是list中节点的定义,用到了模板,现在再对该部分进行解析,其实就是在创建的时候可以根据需要的内容开辟出对应的节点类型

cpp 复制代码
template<class T>
struct list_node
{
	T _data;
	list_node<T>* _next;
	list_node<T>* _prev;

	list_node(const T& x = T())
		:_data(x)
		, _next(nullptr)
		, _prev(nullptr)
	{}
};

有了节点信息,就可以对list做一些基础的操作,例如头插头删,尾插尾删等操作,但对于inserterase这些操作还不能够实现,因此就要实现迭代器模块的内容

不管是对于vector还是list,迭代器的本质就是用一个原生指针去进行访问等等,但是listvector不同的是,list的存储地址并不是连续的,因此在访问的过程中就需要对迭代器进行一定程度的封装,例如在++或者--的操作符上可以进行一些体现,因此list迭代器的实现是需要进行单独的封装的

cpp 复制代码
// 定义正向迭代器
template <class T, class Ref, class Ptr>
class __list_iterator
{
public:
	typedef list_node<T> Node;
	typedef __list_iterator<T, T&, T*> self;
	__list_iterator(Node* node)
		:_node(node)
	{}

	self& operator++()
	{
		_node = _node->_next;
		return *this;
	}
	self& operator++(int)
	{
		self tmp(*this);
		_node = _node->_next;
		return tmp;
	}
	self& operator--()
	{
		_node = _node->_prev;
		return *this;
	}
	self& operator--(int)
	{
		self tmp(*this);
		_node = _node->_prev;
		return tmp;
	}
	Ref operator*()
	{
		return _node->_data;
	}
	Ptr operator->()
	{
		return &_node->_data;
	}
	bool operator !=(const self& s)
	{
		return _node != s._node;
	}
	bool operator ==(const self& s)
	{
		return _node == s._node;
	}
	Node* _node;
};

上面的片段对list进行了一些封装,实现了它的一些基础功能,从代码中也能看出来,迭代器的本质确确实实就是指针,用指针来进行一系列的操作,对下面这几个片段单独进行解析:

cpp 复制代码
	Ptr operator->()
	{
		return &_node->_data;
	}

这是对于迭代器中解引用的运算符重载,这里使用的是&_node->_data的写法,看似很怪,但是实际上这里的函数调用过程应该是这样

也就是说,这里对于->进行运算符重载后,还需要进行解引用,这个运算符重载函数返回的是一个指针,而这个指针还要继续进行解引用才能得到用户想要得到的值,编译器在这里进行了特殊处理,两个->使得可读性下降,因此将两个->进行了一定程度的合并,只需要一个->就可以实现解引用的目的

其次是对模板的使用部分

cpp 复制代码
template <class T, class Ref, class Ptr>

	typedef list_node<T> Node;
	typedef __list_iterator<T, T&, T*> self;

这里在最开始定义的时候,就定义了数据类型,引用和指针三种模板参数,借助这个参数就可以用模板将复杂的内容实现简单化,只需要一份代码,模板就可以直接实例化出用户在调用的时候需要的代码,在进行封装const迭代器的时候,只需要提供的参数改为const版本就可以实现目的,很便捷

这样就实现了正向迭代器的普通版本,而对于const迭代器的版本也只需要进行不同的模板参数就可以实例化出const版本的迭代器

cpp 复制代码
typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<T, const T&, const T*> const_iterator;

有了迭代器,在实现链表的各种函数功能就更加方便,例如可以实现eraseinsert的操作,实现了这两个函数,在进行头插头删,尾插尾删的时候就更加方便,只需要进行原地的调用即可

cpp 复制代码
	// Modifiers
	void push_front(const T& val)
	{
		//Node* newnode = new Node;
		//newnode->_data = val;
		//newnode->_next = _head->_next;
		//_head->_next->_prev = newnode;
		//_head->_next = newnode;
		//newnode->_prev = _head;
		//_size++;
		insert(begin(), val);
	}
	void pop_front()
	{
		//Node* delnode = _head->_next;
		//_head->_next = _head->_next->_next;
		//_head->_next->_prev = _head;
		//delete delnode;
		//delnode = nullptr;
		//_size--;
		erase(begin());
	}
	void push_back(const T& val)
	{
		//Node* newnode = new Node;
		//newnode->_data = val;
		//newnode->_prev = _head->_prev;
		//_head->_prev->_next = newnode;
		//newnode->_next = _head;
		//_head->_prev = newnode;
		//_size++;
		insert(end(), val);
	}
	void pop_back()
	{
		//Node* delnode = _head->_prev;
		//delnode->_prev->_next = _head;
		//_head->_prev = delnode->_prev;
		//delete delnode;
		//delnode = nullptr;
		//_size--;
		erase(--end());
	}
	iterator insert(iterator pos, const T& val)
	{
		Node* cur = pos._node;
		Node* prev = cur->_prev;
		Node* newnode = new Node(val);

		_size++;
		prev->_next = newnode;
		newnode->_prev = prev;
		newnode->_next = cur;
		cur->_prev = newnode;
		return iterator(newnode);
	}
	iterator erase(iterator pos)
	{
		Node* cur = pos._node;
		Node* prev = cur->_prev;
		Node* next = cur->_next;

		delete cur;
		cur = nullptr;
		_size--;

		prev->_next = next;
		next->_prev = prev;
		return iterator(next);
	}

那么上面是对前面已经有过的内容进行的重新温故,但是上面的代码其实是没有实现反向迭代器的,而在STL的库中,反向迭代器的定义和正向迭代器其实并不相同,它是直接借助正向迭代器对反向迭代器进行适配,有些类似于用vectorlist或者deque对栈和队列进行的适配,也体现了封装和代码复用

cpp 复制代码
template<class Iterator, class Ref, class Ptr>
class ReverseIterator
{
public:
	typedef ReverseIterator<Iterator, Ref, Ptr> Self;

	ReverseIterator(Iterator it)
		:_it(it)
	{}

	Self& operator++()
	{
		--_it;
		return *this;
	}

	Ref operator*()
	{
		return *_it;
	}

	Ptr operator->()
	{
		return _it.operator->();
	}

	bool operator!=(const Self& s)
	{
		return _it != s._it;
	}
private:
	Iterator _it;
};

上面的代码就是对于反向迭代器的封装,从中可以看出反向迭代器是使用了正向迭代器的,并且在它的基础上进行的修改,因此这个反向迭代器是可以适配于vector也可以适配于list的

整体来说,对于反向迭代器就是用正向迭代器进行适配出来的,体现了模板的好处

完整代码

cpp 复制代码
#pragma once

namespace mylist
{
	// 定义节点内容
	template <class T>
	struct list_node
	{
		list_node(const T& x = T())
			:_data(x)
			, _next(nullptr)
			, _prev(nullptr)
		{}
		T _data;
		list_node<T>* _next;
		list_node<T>* _prev;
	};

	// 定义正向迭代器
	template <class T, class Ref, class Ptr>
	class __list_iterator
	{
	public:
		typedef list_node<T> Node;
		typedef __list_iterator<T, T&, T*> self;
		__list_iterator(Node* node)
			:_node(node)
		{}

		self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		self& operator++(int)
		{
			self tmp(*this);
			_node = _node->_next;
			return tmp;
		}
		self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}
		self& operator--(int)
		{
			self tmp(*this);
			_node = _node->_prev;
			return tmp;
		}
		Ref operator*()
		{
			return _node->_data;
		}
		Ptr operator->()
		{
			return &_node->_data;
		}
		bool operator !=(const self& s)
		{
			return _node != s._node;
		}
		bool operator ==(const self& s)
		{
			return _node == s._node;
		}
		Node* _node;
	};

	// 定义反向迭代器
	template<class Iterator, class Ref, class Ptr>
	class reverse_iterator
	{
		typedef reverse_iterator<Iterator, Ref, Ptr> self;
	public:
		reverse_iterator(Iterator it)
			:_it(it)
		{}

		self& operator++()
		{
			_it--;
			return *this;
		}
		self& operator++(int)
		{
			self tmp(*this);
			_it--;
			return tmp;
		}
		self& operator--()
		{
			_it++;
			return *this;
		}
		self& operator--(int)
		{
			self tmp(*this);
			_it++;
			return tmp;
		}
		Ref operator*()
		{
			Iterator cur = _it;
			return *(--cur);
		}
		Ptr operator->()
		{
			return &(operator*());
		}
		bool operator !=(const self& s)
		{
			return _it != s._it;
		}
		bool operator ==(const self& s)
		{
			return _it == s._it;
		}

		Iterator _it;
	};

	// 定义链表
	template <class T>
	class list
	{
		typedef list_node<T> Node;
	public:
		typedef __list_iterator<T, T&, T*> iterator;
		typedef __list_iterator<T, const T&, const T*> const_iterator;
		typedef reverse_iterator<iterator, T&, T*> reverse_iterator;
		//typedef reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;
		// Constructor
		list()
		{
			empty_init();
		}
		list(const list<T>& lt)
		{
			for (auto x : lt)
			{
				push_back(x);
			}
		}
		list(iterator begin, iterator end)
		{
			empty_init();
			while (begin != end)
			{
				push_back(begin._node->_data);
				begin++;
			}
		}
		//list(reverse_iterator rbegin, reverse_iterator rend)
		//{
		//	empty_init();
		//	while (rbegin != rend)
		//	{
		//		push_back(rbegin._node->_data);
		//		rbegin++;
		//	}
		//}

		// Destructor
		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}

		// Operator=
		list<T>& operator=(const list<T>& lt)
		{
			swap(lt);
			return *this;
		}

		// Iterators
		iterator begin()
		{
			return iterator(_head->_next);
		}
		iterator end()
		{
			return iterator(_head);
		}
		const_iterator begin() const
		{
			return const_iterator(_head->_next);
		}
		const_iterator end() const
		{
			return const_iterator(_head);
		}
		reverse_iterator rbegin()
		{
			return reverse_iterator(end());
		}
		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}
		//const_reverse_iterator rbegin() const
		//{
		//	return const_reverse_iterator(end());
		//}
		//const_reverse_iterator rend() const
		//{
		//	return const_reverse_iterator(begin());
		//}

		// Capacity
		bool empty()
		{
			return _size == 0;
		}
		size_t size()
		{
			return _size;
		}

		// Element access
		T& front()
		{
			return begin()._node->_data;
		}
		T& back()
		{
			return (--end())._node->_data;
		}

		// Modifiers
		void push_front(const T& val)
		{
			//Node* newnode = new Node;
			//newnode->_data = val;
			//newnode->_next = _head->_next;
			//_head->_next->_prev = newnode;
			//_head->_next = newnode;
			//newnode->_prev = _head;
			//_size++;
			insert(begin(), val);
		}
		void pop_front()
		{
			//Node* delnode = _head->_next;
			//_head->_next = _head->_next->_next;
			//_head->_next->_prev = _head;
			//delete delnode;
			//delnode = nullptr;
			//_size--;
			erase(begin());
		}
		void push_back(const T& val)
		{
			//Node* newnode = new Node;
			//newnode->_data = val;
			//newnode->_prev = _head->_prev;
			//_head->_prev->_next = newnode;
			//newnode->_next = _head;
			//_head->_prev = newnode;
			//_size++;
			insert(end(), val);
		}
		void pop_back()
		{
			//Node* delnode = _head->_prev;
			//delnode->_prev->_next = _head;
			//_head->_prev = delnode->_prev;
			//delete delnode;
			//delnode = nullptr;
			//_size--;
			erase(--end());
		}
		iterator insert(iterator pos, const T& val)
		{
			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* newnode = new Node(val);

			_size++;
			prev->_next = newnode;
			newnode->_prev = prev;
			newnode->_next = cur;
			cur->_prev = newnode;
			return iterator(newnode);
		}
		iterator erase(iterator pos)
		{
			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* next = cur->_next;

			delete cur;
			cur = nullptr;
			_size--;

			prev->_next = next;
			next->_prev = prev;
			return iterator(next);
		}
		void swap(const list<T>& lt)
		{
			std::swap(_head, lt._head);
			std::swap(_size, lt._size);
		}
		void clear()
		{
			Node* cur = _head->_next;
			while (cur != _head)
			{
				Node* next = cur->_next;
				delete(cur);
				cur = next;
			}
			_head->_next = _head;
			_head->_prev = _head;
		}


		void empty_init()
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
			_head->_data = T();
			_size = 0;
		}

		void Print()
		{
			Node* cur = _head->_next;
			while (cur != _head)
			{
				cout << cur->_data << "->";
				cur = cur->_next;
			}
			cout << "null" << endl;
		}
	private:
		Node* _head;
		size_t _size;
	};

	void test_iterator()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);
		cout << "iterator constructor:";
		list<int> lt1(lt.begin(), lt.end());
		lt1.Print();
		cout << "front():" << lt.front() << endl;
		cout << "back():" << lt.back() << endl;
		mylist::__list_iterator<int, int&, int*> it = lt.begin();
		while (it != lt.end())
		{
			std::cout << *it << " ";
			it++;
		}
		cout << endl;
	}
	void test_clear()
	{
		list<int> lt1;
		cout << "push_back:" << endl;
		lt1.push_back(1);
		lt1.push_back(2);
		lt1.push_back(3);
		lt1.push_back(4);
		lt1.Print();
		lt1.clear();
		lt1.push_back(5);
		lt1.push_back(6);
		lt1.push_back(7);
		lt1.push_back(8);
		lt1.Print();
	}
	void test_push_pop()
	{
		list<int> lt1;
		cout << "push_back:" << endl;
		lt1.push_back(1);
		lt1.push_back(2);
		lt1.push_back(3);
		lt1.push_back(4);
		lt1.Print();
		cout << "pop_back:" << endl;
		lt1.pop_back();
		lt1.Print();

		list<int> lt2;
		cout << "push_front:" << endl;
		lt2.push_front(1);
		lt2.push_front(2);
		lt2.push_front(3);
		lt2.push_front(4);
		lt2.Print();
		cout << "pop_front:" << endl;
		lt2.pop_front();
		lt2.Print();
	}
	void test_reverse_iterator()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);
		cout << "iterator constructor:";
		//list<int> lt1(lt.rbegin(), lt.rend());
		//lt1.Print();
		cout << "front():" << lt.front() << endl;
		cout << "back():" << lt.back() << endl;
		mylist::list<int>::reverse_iterator rit = lt.rbegin();
		while (rit != lt.rend())
		{
			std::cout << *rit << " ";
			rit++;
		}
		cout << endl;
	}

	void test()
	{
		test_reverse_iterator();
		//test_push_pop();
		//test_clear();
	}
}
相关推荐
獨枭几秒前
C++ 项目中使用 .dll 和 .def 文件的操作指南
c++
霁月风3 分钟前
设计模式——观察者模式
c++·观察者模式·设计模式
橘色的喵4 分钟前
C++编程:避免因编译优化引发的多线程死锁问题
c++·多线程·memory·死锁·内存屏障·内存栅栏·memory barrier
何曾参静谧40 分钟前
「C/C++」C/C++ 之 变量作用域详解
c语言·开发语言·c++
AI街潜水的八角1 小时前
基于C++的决策树C4.5机器学习算法(不调包)
c++·算法·决策树·机器学习
JSU_曾是此间年少1 小时前
数据结构——线性表与链表
数据结构·c++·算法
此生只爱蛋2 小时前
【手撕排序2】快速排序
c语言·c++·算法·排序算法
何曾参静谧3 小时前
「C/C++」C/C++ 指针篇 之 指针运算
c语言·开发语言·c++
lulu_gh_yu3 小时前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
ULTRA??4 小时前
C加加中的结构化绑定(解包,折叠展开)
开发语言·c++