16.17.list(上)

list的迭代器很麻烦,物理结构不连续。类型对节点指针封装,重载operator*就可以获取里面数据

指针是四个字节,我们用迭代器封装,封装完了还是四个字节,物理上都是地址,但是

行为不同。

可以加上后置加加。没写拷贝构造,编译器默认生成拷贝构造,内置类型,指针也可能是内置类型,这有个迭代器指针走浅拷贝会不会有问题,不会,不会,begin返回第二个位置迭代器,

我期望it也指向这个节点,我要的就是浅拷贝,并不是说我有指针就需要深拷贝,而是看我的指针指向的资源是不是属于你的。链表需要深拷贝,stringvector需要深拷贝,指针指向的资源是指向他的,迭代器指向资源不是属于他的,是属于链表的,不需要深拷贝,仅仅是为了访问遍历链表,不需要深拷贝,更不需要析构,不可能释放,没析构就不需要拷贝构造和赋值。

迭代器模拟的是指针的行为,所以他还需要operator->,结构的指针才需要箭头

cpp 复制代码
struct AA
	{
		int _a1 = 1;
		int _a2 = 1;
	};
void test_list1()
	{	
        list<AA> lta;
		lta.push_back(AA());
		lta.push_back(AA());
		lta.push_back(AA());
		lta.push_back(AA());
		list<AA>::iterator ita = lta.begin();
		while (ita != lta.end())
		{
			
			cout <<*ita<<" ";
			
			++ita;
		}
		cout << endl;
	}

编译不通过,解引用每个数据是data

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

data是T类型,AA,AA不支持流插入,可以给AA重载个流插入,不支持也可以

可以重载个operator->

T是AA,就是返回AA*,这里怎么看怎么奇怪,

第一个箭头完了就是AA*,就可以解引用了,这里严格来说是两个箭头,为了可读性编译器省略了一个箭头,

上节课printcontrainer不仅针对链表,还针对任意容器,所有容器都支持迭代器,就支持for

加入print之后发现范围for不支持,print外面的范围 for支持,里面的就不支持了为什么,

普通容器迭代器替换普通的迭代器,const容器调用const迭代器,我们没有实现const迭代器,跑不了为什么const加个-形成单独类型,而为什么不直接加const修饰,const迭代器是自身不能修改还是指向的内容不能修改,

要第二个 const iterator就修饰迭代器本身不能修改,

如何保证const迭代器指向的内容不能修改,我们现在不是原生指针了,是有个类型进行封装,迭代器修改指向的内容通过operator* 和operator->进行修改,

这就不能修改了,但是普通迭代器还是要改,这里加const迭代器。

cpp 复制代码
template<class T>
	struct list_const_iterator
	{
		typedef list_node<T> Node;
		typedef list_const_iterator<T> Self;
		Node* _node;

		list_const_iterator(Node* node)
			:_node(node)
		{}

		const T& operator*()
		{
			return _node->_data;
		}

		const T* operator->()
		{
			return &_node->_data;
		}

		Self& operator++()
		{
			_node = _node->_next;
			return *this;
		}

		Self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}

		Self operator++(int)
		{
			Self tmp(*this);
			_node = _node->_next;

			return tmp;
		}

		Self& operator--(int)
		{
			Self tmp(*this);
			_node = _node->_prev;

			return tmp;
		}

		bool operator!=(const Self& s) const
		{
			return _node != s._node;
		}

		bool operator==(const Self& s) const
		{
			return _node == s._node;
		}
	};

这重载了begin 和end 版本,

如果有最匹配的就走最匹配的,这是两个不同类模版实现的,没有的时候可以将就一下,普通的 const都可以调用const的,如果有更匹配的就走最匹配的

返回const迭代器这里不匹配了,还得改

模版类模版这些都一样他们会走按需实例化,返回的const 不能修改,但是这里没报错,模版不能生成对应代码,按需实例化是指模版要把具体类型实例化,实例化后才生成具体代码,这个函数模版在这没有调用,编译器基础错误可以检查,也会编译它,会走一层浅浅扫描,看一下大框架不会走细节一些错误,

这种就不会,把这个函数放出来,就报错。把这个+=注释就行了。

但是这里搞一个list------ieetarator 一个list_const_iterator,不好。这两个类相似度太高了,解决一下

看一下库:

用的同一个类模版,但是除了穿了个T还传另外两个参数,

普通迭代器返回T引用和T*,如果const就const引用 * ,也就是说他用同一个类模版,增加两个模版参数去控制。

这两种方式没有本质区别,上面是两个类,类模版是模版,给不同参数,就是不同类型,

cpp 复制代码
	template<class T, class Ref, class Ptr>
	struct list_iterator
	{
		typedef list_node<T> Node;
		typedef list_iterator<T, Ref, Ptr> Self;
		Node* _node;

		list_iterator(Node* node)
			:_node(node)
		{}

		Ref operator*()
		{
			return _node->_data;
		}

		Ptr operator->()
		{
			return &_node->_data;
		}

		Self& operator++()
		{
			_node = _node->_next;
			return *this;
		}

		Self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}

		Self operator++(int)
		{
			Self tmp(*this);
			_node = _node->_next;

			return tmp;
		}

		Self& operator--(int)
		{
			Self tmp(*this);
			_node = _node->_prev;

			return tmp;
		}
		
		bool operator!=(const Self& s) const
		{
			return _node != s._node;
		}

		bool operator==(const Self& s) const
		{
			return _node == s._node;
		}
	};

ref是T引用还是constT引用,不知道看你传,

模版基础上再加模版,实例化出不同对象。模版复用实例化。

看一下迭代器失效的问题,链表里面插入还有没有迭代器失效的问题,没有,

链表不需要挪动数据,对后面关系没改变,erase有没有迭代器失效问题 有

删除之后迭代器野指针,不能++,

,assert的错现在才报出来,按需实例化,之前没调用erase,没细致检查

,野指针迭代器失效,erase会返回下一个位置迭代器

换成库里的会报错,这里list不能写死

我取的是container

这样编不过,我要取模版里的,没实例化的,分不清类型变量,类型加typename,auto也行

insert也有返回值,返回刚插入的元素

析构实现一下,遍历链表一个一个释放,还有个很简单的方法

先实现clear,迭代器外部可以用,内部也可以用

看一下拷贝构造

浅拷贝了但是没蹦,写一个深拷贝:

但是这个代码编不过。可以通过调试来查,pushback需要有哨兵卫的头结点,list2一上来没有哨兵卫头结点,并且形成闭环结构,所以初始化一下

cpp 复制代码
	void empty_init()
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
			_size = 0;
		}

		list()
		{
			empty_init();
		}

		list(initializer_list<T> il)
		{
			empty_init();
			for (auto& e : il)
			{
				push_back(e);
			}
		}

拷贝构造就好了,

赋值不写默认生成的是浅拷贝,此处报错,为什么拷贝构造不报错。搜一搜

用现代写法

相关推荐
cpp_25012 小时前
P1765 手机
数据结构·c++·算法·题解·洛谷
未到结局,焉知生死2 小时前
PAT每日三题11-20
c++·算法
就是ping不通的蛋黄派3 小时前
数据结构与算法—线性表(C++描述)
数据结构·c++
杜子不疼.4 小时前
【C++】深入解析AVL树:平衡搜索树的核心概念与实现
android·c++·算法
永远不打烊4 小时前
c++11 之 统一初始化(Uniform Initalization)
c++·程序员
艾莉丝努力练剑4 小时前
【C++:哈希表封装】用哈希表封装unordered_map和unordered_set
java·c++·stl·哈希算法·散列表·平衡二叉树·哈希
你好,赵志伟5 小时前
Reactor反应堆
网络·c++
y***54885 小时前
C++在游戏引擎中的开发
开发语言·c++·游戏引擎
AA陈超5 小时前
Lyra项目中的输入系统
c++·笔记·学习·游戏·ue5·lyra