list 的迭代器解引用探究
/*list的迭代器解引用探究*/
#if 1
#include <list>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
class Date {
private:
int _year;
int _month;
int _day;
public:
Date()
: _year(2024)
, _month(1)
, _day(1)
{}
void Show() {
cout << _year << "-" << _month << "-" << _day << endl;
}
};
void TestList8() {
list<Date> L1;
L1.push_back(Date());
L1.push_back(Date());
L1.push_back(Date());
L1.push_back(Date());
auto it1=L1.begin();
while(it1!=L1.end()){
it1->Show();
it1++;
}
list<int> L2;
L2.push_back(1);
L2.push_back(2);
L2.push_back(3);
L2.push_back(4);
auto it2=L2.begin();
while(it2!=L2.end()){
cout<<*it2<<endl;
it2++;
}
}
int main() {
TestList8();
}
#endif
这段代码主要展示了如何在 C++ 中使用 std::list
容器来存储和遍历自定义类型(Date
类)的对象以及基本数据类型(int
)的值。程序定义了一个 Date
类,用于表示日期,并提供了一个 Show
成员函数来打印日期。然后,它在函数 TestList8
中创建了两个 std::list
容器:一个存储 Date
对象,另一个存储 int
值。通过迭代器遍历这些列表,并展示了如何访问和操作容器中的元素。
这段代码看似平平无奇,细心的小伙伴可能会发现,在遍历L1
,list
对象的时候,it1->Show();
这一行代码似乎有一点问题。it1
迭代器底层是list
结点的指针,it1->
得到的结果应该是Date
类型对象而不能直接访问Date
类型对象的成员才对。如果it1
底层指针存储的是节点中Date类型的对象的地址,那么it1->Show();
就没有任何问题。
实际上list
类中->
底层会返回*it
迭代器的地址,Ptr operator->(){return &(operator*()); }
,但即使返回了地址,我们还需要一个->
才能访问Date
的对象才对。正确的做法就变成了it1->->Show();
这个样子。但是这样的代码可读性太差了,为了提高代码的可读性,编译器自动给我们添加一个->
,使得我们仅仅使用it1->Show();
这样的代码就可以完成实现。
代码实现
#include<iostream>
using namespace std;
#include<algorithm>
namespace Mylist
{
template<class T>
struct ListNode
{
ListNode<T>* _next;
ListNode<T>* _prev;
T _value;
ListNode(const T& value = T())
: _next(nullptr)
, _prev(nullptr)
, _value(value)
{}
};
// 1. 封装迭代器对应的类
template<class T, class Ref, class Ptr>
struct ListIterator
{
typedef ListNode<T> Node;
typedef Ref ItRef;
typedef Ptr ItPtr;
typedef ListIterator<T, Ref, Ptr> Self;
public:
ListIterator(Node* pNode = nullptr)
: _pNode(pNode)
{}
//
// 具有指针类似的操作
Ref operator*()
{
return _pNode->_value;
}
Ptr operator->()
{
return &(operator*());
}
// 移动
Self& operator++()
{
_pNode = _pNode->_next;
return *this;
}
Self operator++(int)
{
Self temp(*this);
_pNode = _pNode->_next;
return temp;
}
Self& operator--()
{
_pNode = _pNode->_prev;
return *this;
}
Self operator--(int)
{
Self temp(*this);
_pNode = _pNode->_prev;
return temp;
}
///
// 比较
bool operator!=(const Self& s)const
{
return _pNode != s._pNode;
}
bool operator==(const Self& s)const
{
return _pNode == s._pNode;
}
Node* _pNode;
};
// 反向迭代器:就是对正向迭代器的包装
template<class Iterator>
struct ListReverseIterator
{
// 静态成员变量也可以通过类名::静态成员变量名称
// typedef Iterator::ItRef Ref; 编译报错
// 编译器无法在编译时无法确定ItRef是静态成员变量 还是 类型
// 需要显式告诉编译器ItRef就是Iterator类中的类型
// typename
typedef typename Iterator::ItRef Ref;
typedef typename Iterator::ItPtr Ptr;
typedef ListReverseIterator<Iterator> Self;
public:
ListReverseIterator(Iterator it)
: _it(it)
{}
Ref operator*()
{
Iterator temp(_it);
--temp;
return *temp;
}
Ptr operator->()
{
return &(operator*());
}
Self& operator++()
{
--_it;
return *this;
}
Self operator++(int)
{
Self temp(*this);
--_it;
return temp;
}
Self& operator--()
{
++_it;
return *this;
}
Self operator--(int)
{
Self temp(*this);
++_it;
return temp;
}
bool operator!=(const Self& rit)const
{
return _it != rit._it;
}
bool operator==(const Self& rit)const
{
return _it == rit._it;
}
Iterator _it;
};
template<class T>
class list
{
typedef ListNode<T> Node;
// 2. 在容器中给迭代器类型取别名---public
public:
typedef ListIterator<T, T&, T*> iterator;
typedef ListIterator<T, const T&, const T*> const_iterator;
typedef ListReverseIterator<iterator> reverse_iterator;
typedef ListReverseIterator<const_iterator> const_reverse_iterator;
public:
// 注意:list的迭代器一定不能是原生态的指针
// vector之所以可以,因为vector底层是连续空间
// 如果指针指向连续的空间,对指针++/--,该指针就可以移动到下一个/前一个位置
// 但是list不行,因为链表中的节点是通过next和prev指针组织起来的,不一定连续
// 如果将list的迭代器设置为原生态指针,++it/--it没有意义
// typedef Node* iterator; // ???
public:
// 构造
list()
{
CreateHead();
}
list(int n, const T& value = T())
{
CreateHead();
for (int i = 0; i < n; ++i)
{
push_back(value);
}
}
template<class Iterator>
list(Iterator first, Iterator last)
{
CreateHead();
while (first != last)
{
push_back(*first);
++first;
}
}
list(const list<T>& L)
{
CreateHead();
auto it = L.cbegin();
while (it != L.cend())
{
push_back(*it);
++it;
}
}
list<T>& operator=(list<T> L)
{
this->swap(L);
return *this;
}
~list()
{
clear();
delete _head;
_head = nullptr;
}
//
// 迭代器
// 3. 增加begin和end的方法
iterator begin()
{
/*iterator ret(_head->_next);
return ret;*/
return iterator(_head->_next);
}
iterator end()
{
return iterator(_head);
}
const_iterator cbegin()const
{
/*iterator ret(_head->_next);
return ret;*/
return const_iterator(_head->_next);
}
const_iterator cend()const
{
return const_iterator(_head);
}
reverse_iterator rbegin()
{
return reverse_iterator(end());
}
reverse_iterator rend()
{
return reverse_iterator(begin());
}
const_reverse_iterator crbegin()const
{
return const_reverse_iterator(cend());
}
const_reverse_iterator crend()const
{
return const_reve