Bootstrap

list的迭代器模拟实现和迭代器失效(续)

list的迭代器

对迭代器进行封装,迭代器的指针还是4个字节,在物理上是一样的,但是底层是完全不同的
迭代器是浅拷贝,因为list是不属于迭代器的,迭代器只是进行访问(指针)

operator->

为了增强可读性,operator变为了一个->

T* operator->()
{
   // ->的优先级高于&
   return &_node->_data;
}
struct AA
{
	int aa1 = 1;
	int aa2 = 2;
};

void test_list2()
{
	list<AA> lt;
	lt.push_back(AA());
	lt.push_back(AA());
	lt.push_back(AA());
	lt.push_back(AA());
	lt.push_back(AA());

	list<AA>::iterator it = lt.begin();
	while (it != lt.end())
	{
		// *it解引用拿到的是AA对象,对象.进行访问
		//cout << (*it).aa1 << ":" << (*it).aa2 << endl;
		// it->返回的是指针,指针aa1看起来很奇怪
		// 其实是省略了一个->,it.operator()->
		//cout << it->aa1 << ":" << it->aa2 << endl;
		cout << it.operator->()->aa1 << ":" << it.operator->()->aa2 << endl;
		++it;
	}
	cout << endl;

普通迭代器和const迭代器

  • const_iterator是指向的内容不能修改
  • const iterator是指针本身不能修改,使用了这种迭代器的遍历是不能使用了
下面这两个就是指向的内容不能被修改,权限缩小了
const T& operator*()
{
	return _node->_data;
}

// ->
const T* operator->()
{
	return &_node->_data;
}
  • 普通迭代器(可读可写)
template<class T>
struct list_iterator
{
	typedef list_node<T> Node;
	typedef list_iterator<T> Self;
	Node* _node;

	// 构造
	list_iterator(Node* node)
		:_node(node)
	{}

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

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

	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)
	{
		// *this是迭代器
		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;
	}
};

  • const迭代器(只读不能写)
// const_iterator
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++(int)
	{
		Self tmp(*this);
		_node = _node->_next;

		return tmp;
	}

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

	// 后置--
	Self& operator--(int)
	{
		// *this是迭代器
		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;
	}
};
  • 按需实例化(调用了才会实例化)
    类模版是按照需求进行实例化,编译器对模版只是浅浅的扫描,有没有大的语法错误,细节不会检查出来
    细节比如:*it += 10 , 指向的内容不能被修改
// 按需实例化
template<class Container>
void print_container(const Container& con)
{
	typename Container::const_iterator it = con.begin();

	while (it != con.end())
	{
		// *it += 10;

		cout << *it << " ";
		++it;
	}
	cout << endl;

	for (auto ch : con)
	{
		cout << ch << " ";
	}
	cout << endl;

}

void test_list1()
{
	list<int> ls;

	ls.push_back(1);
	ls.push_back(2);
	ls.push_back(3);
	ls.push_back(4);
	ls.push_back(5);


	list<int>::iterator it = ls.begin();
	while (it != ls.end())
	{
		*it += 10;

		cout << *it << endl;
		++it;
	}
	cout << endl;

	for (auto ch : ls)
	{
		cout << ch << " ";
	}
	cout << endl;

    // 只有调用了print_container才会报错
    // 调用了模版才会实例化
    // const_iterator不能修改指向的内容
	print_container(ls);
}

迭代器模版

用模版实例化就不用写高度相似的两个迭代器了
只是这样的模版比较奇怪
实现了类模版给编译器,编译器根据参数不同实例化出两个不同的类
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

迭代器失效

  • list的insert迭代器不失效,不是连续的空间
// insert之后迭代器不失效
void test_list3()
{
	list<int> ls;

	ls.push_back(1);
	ls.push_back(2);
	ls.push_back(3);
	ls.push_back(4);
	ls.push_back(5);

	list<int>::iterator it = ls.begin();
	ls.insert(ls.begin(), 10);
	(*it) *= 11;

	for (auto e : ls)
	{
		cout << e << " ";
	}
	cout << endl;

}
  • erase以后迭代器失效

erase之后是野指针,++it

// 删除
iterator erase(iterator pos)
{
	// 不能删除哨兵位的头节点
	assert(pos != end());

	Node* cur = pos._node;
	Node* prev = cur->_prev;
	Node* next = cur->_next;

	prev->_next = next;
	next->_prev = prev;

	delete cur;
	--_size;

	return next;
}

it = ls.begin();
while (it != ls.end())
{
	if (*it % 2 == 0)
	{
		it = ls.erase(it);
	}
	else
	{
		++it;
	}
}
print_container(ls);

析构

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

void clear()
{
	// iterator it = _head->_next;
	auto it = begin();
	while (it != end())
	{
		it = erase(it);
	}
}

拷贝构造

void test_list4()
{
	list<int> ls;

	ls.push_back(1);
	ls.push_back(2);
	ls.push_back(2);
	ls.push_back(3);
	ls.push_back(4);
	ls.push_back(5);

	// 拷贝构造
	list<int> lt(ls);

	print_container(ls);
	print_container(lt);
}

赋值重载

// 赋值重载
// ls1 = ls3
list<T>& operator=(list<T> ls)
{
	swap(ls);
	return *this;
}

void swap(list<T>& ls)
{
	std::swap(_head,ls._head);
	std::swap(_size, ls._size);
}

// 赋值重载
lt = ls;
print_container(ls);
print_container(lt);

initializer_list

底层是两个指针,指向维护的数组,一个是指向开始位置的指针,一个是指向结束位置的指针

void func(const list<int>& ls)
{
	print_container(ls);
}

void test_list5()
{
	 std::list<int> lt1 = { 1,2,3,4,5,6 };
	 auto lt2 = { 1,2,3,4,5,6 };

	 // 直接构造
	 // 使用了初始化列表构造lt3
	 // C++11用初始化列表直接构造
	 list<int> lt3({ 1,2,3,4,5,6 });
	 // 隐式类型转换
	 list<int> lt4 = { 1,2,3 };
	 // 引用的是{1,2,3,4,5,6}隐式类型转化为list<int>的临时对象
	 const list<int>& lt5 = { 1,2,3,4,5,6 };

	 func(lt3);
	 func({1,2,3});
}
;