目录
1. 结构框架
node是一个结构体,成员有date next prev (public)其他类可以访问
list是链表类,可以以一个指针去访问,增删查改功能函数的实现
iterator是迭代器,方便对于链表结构的访问
2. iterator
为什么使用迭代器,对指针的封装,而不使用原生指针
链表在空间不连续,指针的加减不能很好的访问,通过类定义,内部实现运算符重载
实现iterator类包含一个node*的指针,实现++,--,!= ,*
但是const_iterator怎么实现呢?
typedef const iterator<T> const_iterator;
这样子可行吗?
显然这不行,const_iterator迭代器,目的是date的内容不能被改变,需要可以++和--在链表节点之间访问。
所以迭代器需要三个模板参数,分别对应
数据类型(T)
*返回值(T&或const T&)
->返回值(T*或const T*)
typedef iterator<T, T&, T*> iterator;
typedef iterator<T, const T&, const T*> const_iterator;
当类包含一个指针指向一个对象,那么const 这个类,这个指针指向不能改变,指向的对象反而可以修改
3. 临时对象
临时对象具有常性,出现的场景有匿名对象,隐式类型转换和函数的返回值。
匿名对象
匿名对象具有常性
T是模板可以是任何类型
T() 匿名对象 只在当前行有效,但是如果是
const T& val = T();
那么匿名对象的生命周期就和val一样,因为val就是匿名对象的名字。
隐式类型转换
double a = 1;
1默认是int类型的在赋值之前,产生了一个临时变量是double类型的1.0,如何再赋值给a;
这个中间产生的临时变量具有常性,不可以被改变,真正具有const性质
自定义类型也可以隐式类型转换,前提是自定义类型具有只有一个参数的构造
函数返回值
当函数的返回值是内置类型int,double等,返回值产生的临时对象其实是const int ,const double
返回值是指针类型,int* 临时对象其实是int* const类型
自定义类型作为返回值虽然具有常性,但是可以改变
iterator end()
{
return iterator(_head);
}
void pop_back()
{
erase(--end());
}
返回的是iterator自定义类型
--end()可行,因为自定义类型的临时对象具有常性,但不是真正的具有常性,可以被修改
4. 拷贝构造和赋值重载的复用写法
构造函数
list()
{
_head = new node;
}
template<class InputIterator>
list(InputIterator first, InputIterator last)
{
_head = new node;
while (first != last)
{
push_back(*first);
++first;
}
}
拷贝构造的传统写法
list(const list<T>& x)
{
_head = new node;
for (auto e : x)
{
push_back(e);
}
}
拷贝构造的现代复用写法
list(const list<T>& x)
{
_head = new node;
list<T> tmp(x.begin(), x.end());
swap(tmp);
}
拷贝构造利用前面的迭代器区间构造,构造函数创建tmp局部对象,然后swap交换_head,这样子*this就是和拷贝出来一样,然后对tmp析构
切记要对*this初始化,_head要分配空间,要不然析构tmp的时候就会崩溃
赋值重载的现代复用写法
list<T>& operator=(list<T> x)
{
_head = new node;
swap(x);
return *this;
}
步骤:
1. list<T> x x是拷贝构造出来的局部对象
2. 对*this进行初始化分配空间
3. 交换_head实现内容交换
4. 返回*this 可以引用返回
5. 析构x局部变量
5. list实现源码
list.h
#pragma once
#include <iostream>
#include <list>
#include <assert.h>
using namespace std;
namespace kele
{
template<class T>
struct list_node
{
typedef list_node<T> node;
node* _next;
node* _prev;
T _date;
list_node(const T& val = T())
{
_date = val;
_next = this;
_prev = this;
}
};
template<class T,class Ref,class Ptr>
struct __list_iterator
{
typedef list_node<T> node;
typedef __list_iterator<T, Ref, Ptr> self;
node* _it;
__list_iterator(node* x)
:_it(x)
{}
Ref operator*()
{
return _it->_date;
}
Ptr operator->()
{
return &_it->_date;
}
self operator++()
{
_it = _it->_next;
return *this;
}
self operator++(int)
{
self tmp = *this;
_it = _it->_next;
return tmp;
}
self operator--()
{
_it = _it->_prev;
return *this;
}
self operator--(int)
{
self tmp = *this;
_it = _it->_prev;
return tmp;
}
bool operator!=(const self& x) const
{
return _it != x._it;
}
bool operator==(const self& x) const
{
return _it == x._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;
list()
{
_head = new node;
}
template<class InputIterator>
list(InputIterator first, InputIterator last)
{
_head = new node;
while (first != last)
{
push_back(*first);
++first;
}
}
/*list(const list<T>& x)
{
_head = new node;
for (auto e : x)
{
push_back(e);
}
}*/
list(const list<T>& x)
{
_head = new node;
list<T> tmp(x.begin(), x.end());
swap(tmp);
}
list<T>& operator=(list<T> x)
{
_head = new node;
swap(x);
return *this;
}
~list()
{
clear();
delete _head;
_head = nullptr;
}
iterator begin()
{
return iterator(_head->_next);
}
const_iterator begin() const
{
//_head = _head->_next;
return const_iterator(_head->_next);// const node* const _head
}
iterator end()
{
return iterator(_head);
}
const_iterator end() const
{
return const_iterator(_head);
}
void push_back(const T& val)
{
//node* tail = _head->_prev;
//node* newnode = new node(val);
//tail->_next = newnode;
//newnode->_prev = tail;
//newnode->_next = _head;
//_head->_prev = newnode;
insert(end(), val);
//为什么可以--end()
//因为自定义类型的临时对象具有常性,但不是真正的具有常性,可以被修改
}
void push_front(const T& val)
{
insert(begin(), val);
}
void pop_back()
{
erase(--end());
}
void pop_front()
{
erase(begin());
}
void insert(iterator pos, const T& val)
{
node* prev = pos._it->_prev;
node* next = pos._it;
node* newnode = new node(val);
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = next;
next->_prev = newnode;
}
iterator erase(iterator pos)
{
assert(pos != end());
node* prev = pos._it->_prev;
node* next = pos._it->_next;
delete pos._it;
prev->_next = next;
next->_prev = prev;
return iterator(next);
}
void clear()
{
/*while (!empty())
{
erase(begin());
}*/
iterator it = begin();
while (it != end())
{
/*it = erase(it);*/
erase(it++);
}
}
void swap(list<T>& x)
{
std::swap(this->_head, x._head);
}
bool empty()
{
return begin() == end();
}
private:
node* _head;
};
}
test.cpp
#include"list.h"
struct AA
{
int date1;
int date2;
AA(int date1 = 0, int date2 = 0)
:date1(date1),
date2(date2)
{}
};
class Ptr
{
public:
Ptr(AA& val)
:p(&val)
{}
void print() const//const Ptr* const this
{
//this->p->date1
cout << ++(p->date1) << ":" << p->date2 << endl;
}
private:
AA* p;
};
void Print(const kele::list<int>& lt)
{
kele::list<int>::const_iterator it = lt.begin();
while (it != lt.end())
{
//(*it)++;
cout << *it << " ";
++it;
}
cout << endl;
}
void test1()
{
kele::list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
Print(lt);
lt.insert(lt.begin(), 10);
Print(lt);
lt.erase(lt.begin());
Print(lt);
lt.push_front(100);
lt.push_back(1000);
Print(lt);
lt.pop_back();
lt.pop_front();
Print(lt);
}
//void test2()
//{
// kele::list<AA> lt;
// lt.push_back(AA(1, 1));
// lt.push_back(AA(2, 1));
// lt.push_back(AA(3, 1));
// lt.push_back(AA(4, 1));
// kele::list<AA>::const_iterator it = lt.begin();
// while (it != lt.end())
// {
// cout << it->date1 << ":" << it->date2 << endl;
// ++it;
// }
// cout << endl;
//}
void test3()
{
AA a(1,2);
Ptr p(a);
p.print();
}
void test4()
{
AA a(1, 2);
const AA* p = &a;
//(p->date1)++;
}
void test5()
{
kele::list<int> lt;
/*kele::list<int> lt2;*/
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
Print(lt);
/*lt2 = lt;*/
kele::list<int> lt2(lt);
Print(lt2);
}
int main()
{
test3();
return 0;
}
完。