stl源码剖析_C++进阶系列之STL(1)剖析List部分源码

1、STL 库函数的设计第一位是通用性,模板为其提供了可能;标准模板库中的所有算法和容器都是通过模板实现的。 STL(标准模板库)是 C++最有特色,最实用的部分 之一。 STL整个架构模型如下:

05f6a718389b8fe7ac05aaa4fbab7991.png

2、list(双向循环链表) 调用STL系统的#include,用系统的双向循环链表结构处理:
#include
#include //调用系统的list,双向循环链表结构
using namespace std;

int main(void){

list<int> mylist;
for(int i = 1; i <= 10; i++){
mylist.push_back(i); //接口,末尾增加
}
list<int>::iterator it = mylist.begin(); //迭代器,
while(it != mylist.end()){
cout<it<<"-->"; //打印内部数字++it; //每次往后移一个}
cout<<"NULL"<<endl;}
3、list部分源码实现剖析 list模型如下:

e428c724e82d2308e1f8189ca355cfb2.png

阅读其源代码,分析了部分的功能:
#ifndef _LIST_H   //条件宏编译,避免重复定义
#define _LIST_H

#include //断言引入的头文件
#include //申请空间所引入的头文件

template<class _Ty> //此处先不涉及空间置配器
class list{ //list类
public:
struct _Node;
typedef struct _Node* _Nodeptr; //指向节点的指针类型
struct _Node{ //_Node这个是节点类型
_Nodeptr _Prev; //前驱节点
_Nodeptr _Next; //后继节点
_Ty _Value; //模板数据类型
};
struct _Acc{ //定义_Acc这个类型
typedef struct _Node*& _Nodepref; //指向节点类型指针的引用
typedef _Ty& _Vref; //这个数据类型的引用
static _Nodepref _Next(_Nodeptr _P)//静态方法, 返回值是节点指针的引用 ,参数是指向节点的指针
{return ((_Nodepref)(*_P)._Next);}//:*_P得到这个节点,()强制类型转换的优先级没有.高,所以此时先取_Next,在进行强制类型转换的工作,返回一个指向节点指针的引用。
static _Nodepref _Prev(_Nodeptr _P)
{return ((_Nodepref)(*_P)._Prev);}
static _Vref _Value(_Nodeptr _P)
{return ((_Vref)(*_P)._Value);}
};
public: //以下的类型是_A这个类下面的类型,_A这个类在空间置配器中定义
typedef typename _A::value_type value_type;
typedef typename _A::pointer_type pointer_type;
typedef typename _A::const_pointer_type const_pointer_type;
typedef typename _A::reference_type reference_type;
typedef typename _A::const_reference_type const_reference_type;
typedef typename _A::size_type size_type; //这个类型其实就是size_t

private:
_Nodeptr _Head; //指向头结点的指针
size_type _Size; //有几个节点个数
};

#endif
以上代码主要是struct  _Acc这个类的理解好至关重要!!! 下面就是构造函数和析构函数了。
public:
explicit list():_Head(_Buynode()),_Size(0) //explicit显示调用此构造函数,给头一个指向,刚开始0个
{}
~list()
{ //释放空间和空间配置器有关,在现阶段先不关心。
erase(begin(), end()); //调用开始,结束函数释放空间;
_Freenode(_Head); //释放头;
_Head = 0, _Size = 0; //都赋空;
}
..................................................
protected:
_Nodeptr _Buynode(_Nodeptr _Narg=0, _Nodeptr _Parg=0) // 返回值为节点指针类型,参数都为节点指针类型,传的应该是后继和前驱指针,默认都为0;
{
_Nodeptr _S = (_Nodeptr)malloc(sizeof(_Node));//申请一个节点空间,把地址给了_S;

assert(_S != NULL); //所申请的空间存在的话
_Acc::_Next(_S) = _Narg!=0 ? _Narg : _S; //给新生成的节点的_Next赋值
_Acc::_Prev(_S) = _Parg!=0 ? _Parg : _S; //给新生成的节点的_Prev赋值
return _S; //返回这个新生成节点的地址
}
//这个_Buynode函数的意思是:当创建的是第一个节点时,自己一个节点连向自己,构成双向循环链表,其他的情况则是插入到两个节点之间!!!
........................................................
接下来写迭代器:
public:
class iterator{ //迭代器也是一个类,是list的内部类;
public:
iterator()
{}
iterator(_Nodeptr _P):_Ptr(_P)
{}
public:
iterator& operator++(){ // ++it,前++的运算符重载
_Ptr=_Ptr->_Next; //因为是链表结构,内部实现迭代器的++,是进行了++的重载;使其指针的移动到下一个节点;
return *this; //返回的是这个节点的引用。
}
iterator operator++(int)// it++
{
_It it(_Ptr); //先保存原先节点
_Ptr = _Ptr->_Next; //移到下一个节点
return it; //返回原先的;
}
iterator operator--(int); //类似
iterator& operator--();
reference_type operator*()const //对*的重载
{return _Ptr->_Value;} //返回这个节点的_Value值
pointer_type operator->()const //对->的重载
//{return &_Ptr->_Value;} 自己实现的,->的优先级高于&,所以将_Value的地址返回
{return (&**this);} //系统中的,this是迭代器的地址,*this是迭代器对象,再来一个*时,调用上面的(对*的重载),此时还是返回_Value的地址。
public:
bool operator!=(const iterator &it)const //迭代器对象的比较
{return _Ptr!=it._Ptr;} //比的是指向节点的指针;
public:
_Nodeptr _Mynode()const //得到当前节点的地址;
{return _Ptr;}
protected:
_Nodeptr _Ptr; //迭代器的数据成员是一个指向节点的指针。
};
typedef iterator _It; //_It 就是迭代器类型
public:
iterator begin(){return iterator(_Acc::_Next(_Head));} //begin()函数得到头结点的后继(第一个有效节点的地址)
iterator begin()const;
iterator end(){return iterator(_Head);} //end()函数得到的是头结点(也就是最后一个节点的后继地址);
public: //前面的已经讲的很清楚了,后面的都是调用即可;
void push_back(const _Ty &x)
{insert(end(),x);}
void push_front(const _Ty &x)
{insert(begin(),x);}
public:
iterator insert(iterator _P, const _Ty &_X=_Ty())
{
_Nodeptr _S = _P._Mynode(); //得到节点地址
_Acc::_Prev(_S) = _Buynode(_S, _Acc::_Prev(_S)); //下面的三句调用前面的函数_Buynode()实现了插入功能;
_S = _Acc::_Prev(_S);
_Acc::_Next(_Acc::_Prev(_S)) = _S;
++_Size; //个数加1
return iterator(_S);
}
void insert(iterator _P, size_type _M, const _Ty &_X) //插入个数_M个,以下几个调用前面函数;
{
for(; 0<_M; --_M)
insert(_P,_X);
}
void insert(iterator _P, const _Ty *_F, const _Ty *_L) //区间的插入
{
for(; _F!=_L; ++_F)
insert(_P, *_F);
}
void insert(iterator _P, _It _F, _It _L) //迭代器的插入
{
for(; _F!=_L; ++_F)
insert(_P, *_F);
}
/*
void push_back(const _Ty &x) //尾随增加最后
{
_Nodeptr _S = _Buynode(_Head, _Acc::_Prev(_Head)); //实现插入功能
_Acc::_Value(_S) = x;
_Acc::_Next(_Acc::_Prev(_Head)) = _S;
_Acc::_Prev(_Head) = _S;
_Size++; //最后加1
}
iterator erase(iterator _P)// 删除空间
{
_Nodeptr _S = (_P++)._Mynode();
_Acc::_Next(_Acc::_Prev(_S)) = _Acc::_Next(_S);
_Acc::_Prev(_Acc::_Next(_S)) = _Acc::_Prev(_S);
--_Size; //个数减少1个
return _P;
}
iterator erase(iterator _F, iterator _L) //调用函数,删除区间
{
while(_F != _L)
erase(_F++);
return _F;
}
void clear() //清除所有空间
{erase(begin(), end());}
#endif
4、总结 (1)、迭代器的本质有了了解,是一个内部类,它将是一个对象,内部数据成员是一个指向节点的指针; (2)、迭代器对->的重载返回的是节点内部数据的地址,而不是节点的地址; (3)、迭代器对每种数据结构的实现均不相同,(Stack, queue, list...........) (4)、空间配置器:对所有的数据结构而言,只有一份, 作用:申请,释放空间,构造,析构对象; 推荐阅读: C++进阶系列之Boost库智能指针(1)---智能指针VC版 C++进阶系列之Boost库智能指针(2)---VS/Linux版的auto_ptr C++进阶系列之Boost库智能指针(3)---scoped_ptr C++进阶系列之Boost库智能指针(4)---scoped_array C++进阶系列之Boost库智能指针(5)---shared_ptr(上) C++进阶系列之Boost库智能指针(6)---shared_ptr(下) C++进阶系列之Boost库智能指针(7)---shared_array C++进阶系列之Boost库智能指针(8)---weak_ptr和intrusive_ptr 一起学习技术

270275689037e533f4763eb5ae5a4c0c.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值