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});
}