STL源码剖析 list概述

53 篇文章 1 订阅
31 篇文章 2 订阅

目录

list的节点(node)

list迭代器

 list 的构造和内存管理

list 的元素操作

  •  list相较于vector连续的线性空间就显得很复杂,他的存储空间是不连续的,好处是每次插入和删除一个元素的时候,只需要配置或者释放一个元素的空间

  • 插入和删除十分的方便

list的节点(node)

  • list 本身和list的节点是不同的结构,需要分开设计
  • list节点结构是一个双向的链表
template <class T>
struct __list_node{
    typedef void* void_pointer;
    void_pointer prev;   //指针的类型是void*,其实可以将其设定为 __list_node<T>
    void_pointer next;   
    T data;
};

list迭代器

  • list迭代器不能像vector一样使用普通的指针,因为考虑到内存分配的不连续性,list的迭代器必须有能力指向list的的节点,并正确的进行递增、递减、取值(获取成员节点的数据值)、成员的存取(取用的是节点的成员)等操作
  • 因为list的迭代器具备前移和后移的能力,所以使用Bidirectional iterators
  • list的插入和接合操作(splice)都不会造成原有的list迭代器失效,vector不可以,因为vector插入操作可能造成记忆体的重新配置,会导致原有的迭代器失效
  • list删除元素(erase)也只有指向被删除元素的那个迭代器会失效,其余的迭代器不会受到任何的影响

  •  list迭代器设计如下
//list的迭代器设计
template <class T,class Ref,class Ptr>
struct __list_iterator{
    typedef __list_iterator<T,T&,T*>    iterator;
    typedef __list_iterator<T,Ref,Ptr>  self;
    typedef std::bidirectional_iterator_tag iterator_category;
    typedef T value_type;
    typedef Ptr pointer;
    typedef Ref reference;
    typedef __list_node<T>* link_type;
    typedef std::size_t size_type;
    typedef ptrdiff_t difference_type;

    link_type node;//迭代器内部需要一个普通的指针,指向list节点

    //constructor
    __list_iterator(){}
    __list_iterator(link_type x):node(x){}
    __list_iterator(const iterator& x):node(x.node){}

    bool operator==(const self& x) const{return (node == x.node);}
    bool operator!=(const self& x) const{return (node != x.node);}

    //以下对迭代器取值 取得的是节点的数据值
    reference operator*() const {return (*node).data;}
    //以下是对迭代器的成员进行存取 (member access) 运算子的标准做法
    pointer operator->() const {return &(operator*());}

    //对迭代器进行加一 前进一个节点
    self& operator++(){
        node = (link_type)((*node).next);
    }
    
    self operator++(int){
        self tmp = *this;
        ++*this;
        return tmp;
    }
    
    //对迭代器进行减一 后退一个节点
    self& operator--(){
        node = (link_type)((*node).prev);
    }
    
    self operator--(int){
        self tmp = *this;
        --*this;
        return tmp;
    }
};

list的数据结构

  • SGI list不仅仅是双向链表 还是一个环状双向链表,只需要一个指针就可以完成整个链表的遍历
//list的迭代器设计
template <class T,class Ref,class Ptr>
struct __list_iterator{
    typedef __list_iterator<T,T&,T*>    iterator;
    typedef __list_iterator<T,Ref,Ptr>  self;
    typedef std::bidirectional_iterator_tag iterator_category;
    typedef T value_type;
    typedef Ptr pointer;
    typedef Ref reference;
    typedef __list_node<T>* link_type;
    typedef std::size_t size_type;
    typedef ptrdiff_t difference_type;

    link_type node;//迭代器内部需要一个普通的指针,指向list节点

    //constructor
    __list_iterator(){}
    __list_iterator(link_type x):node(x){}
    __list_iterator(const iterator& x):node(x.node){}

    bool operator==(const self& x) const{return (node == x.node);}
    bool operator!=(const self& x) const{return (node != x.node);}

    //以下对迭代器取值 取得的是节点的数据值
    reference operator*() const {return (*node).data;}
    //以下是对迭代器的成员进行存取 (member access) 运算子的标准做法
    pointer operator->() const {return &(operator*());}

    //对迭代器进行加一 前进一个节点
    self& operator++(){
        node = (link_type)((*node).next);
    }

    self operator++(int){
        self tmp = *this;
        ++*this;
        return tmp;
    }

    //对迭代器进行减一 后退一个节点
    self& operator--(){
        node = (link_type)((*node).prev);
    }

    self operator--(int){
        self tmp = *this;
        --*this;
        return tmp;
    }

    //让指针node刻意指向尾端的一个空白节点,node节点便会符合STL对于前开后闭区间的要求,成为list迭代器
    iterator begin(){return (link_type)(*node->next);}
    iterator end(){return node;}
    bool empty()const{return node->next == node;}
    size_type size()const{
        size_type result = 0;
        std::distance(begin(),end(),result);
        return result;
    }
    //取头部节点的内容(元素数值)
    reference front(){
        return *begin();
    }
    //取尾节点的内容(元素数值)
    reference back(){
        return *(--end());
    }
};
//list 环状双向链表设计如下
template <class T,class Alloc> //缺省使用alloc作为配置器
class list{
protected:
    typedef __list_node<T> list_node;
public:
    typedef list_node* link_type;
protected:
    link_type node; //只需要一个指针,便可以循环遍历整个环状的双向链表
};

 list 的构造和内存管理

  • 具体内容见代码注释
//list 环状双向链表设计如下
template <class T,class Alloc> //缺省使用alloc作为配置器
class list{

protected:
    typedef __list_node<T> list_node;
    //专属空间配置器 每次配置一个节点的大小
public:
    typedef list_node* link_type;
    typedef simple_alloc<list_node,Alloc>list_node_allocator;
    //list_node_allocator(n) 表示分配n个节点空间,以下四个函数分别用来配置、释放、构造、销毁一个节点
protected:
    //配置一个节点并返回
    link_type get_node(){return list_node_allocator::allocate();}
    //释放一个节点
    link_type put_node(){return list_node_allocator::deallocate();}
    //产生(配置并构造)一个节点 带有元素数值
    link_type create_node(const T& x){
        link_type p = get_node();
        Chy::allocator<T>::construct(p->data,x); //全局函数 构造/析构基本工具
        return p;
    }
    //销毁 (析构并释放) 一个节点
    void destroy_node(link_type p){
        Chy::allocator<T>::destroy(&p->data);  //全局函数 构造/析构基本工具
    }

public:
    //构造函数
    //产生一个空的链表
    list(){empty_initialize();} //产生一个空的链表
protected:
    link_type node; //只需要一个指针,便可以循环遍历整个环状的双向链表
    void empty_initialize(){
        node = get_node();  //配置一个节点空间,令node指向它
        node->next = node;  //令node头尾指向自己  不设置元素值
        node->prev = node;  
    }
};

  •  当使用push_back()将新的元素插入到list的尾端的时候 ,这个函数内部调用的是insert();

list 的元素操作

//清除所有的节点(整个链表)
template <class T,class Alloc>
void list<T,Alloc>::clear() {
    link_type cur = (link_type)node->next; //begin()
    while (cur != node){   //遍历每一个节点
        link_type tmp = cur;
        cur = (link_type)cur->next;
        destroy_node(tmp); //销毁、析构释放一个节点
    }
    //恢复node的原始状态
    node->next = node;
    node->prev = node;
}

//清除数值为value的所有元素
template<class T,class Alloc>
void list<T,Alloc>::remove(const T &value) {
    typedef typename __list_iterator<T,T&,T*>::iterator iterator;
    iterator first = __list_iterator<T,T&,T*>::begin();
    iterator last = __list_iterator<T,T&,T*>::end();
    while (first != last){
        iterator next = first;
        ++next;
        if (*first == value){
            __list_iterator<T,T&,T*>::erase(value);
            first = next;
        }
    }
}

//移除数值相同的连续元素,注意:只有"连续并且相同的元素",才会被删除只剩一个
template <class T,class Alloc>
void list<T,Alloc>::unique() {
    typedef typename __list_iterator<T,T&,T*>::iterator iterator;
    iterator first = __list_iterator<T,T&,T*>::begin();
    iterator last = __list_iterator<T,T&,T*>::end();
    if (first == last){
        return; //空的链表  什么都不做
    }
    iterator next = first;
    while(++next != last){       //遍历每一个节点
        if (*first == *next){    //如果这个区段中存在相同的元素
            __list_iterator<T,T&,T*>::erase(next); //移除之
        } else{
            first = next;        //调整指针
        }
        next = first;            //修正区段范围
    }
}
  • list是一个双向的环状链表,只需要处理边界条件,在头部和尾部插入和删除的操作几乎是一样的
  • 移除(erase) 某个迭代器所指向的元素,只是进行指针移动操作

  • list提供了一个迁移操作(transfer),将连续范围的元素迁移到某个特定位置之前,技术角度上讲是节点之间的指针移动
  • transfer迁移操作 是 其余操作(splice 、 sort 、 merge)的基础
  • transfer的源代码 

  • transfer接收的[first , last)区间可以在同一个list中
  • transfer不是公开的接口,list提供的是所谓的接合操作(splice) ,将某联系范围的元素从一个list移动到另一个(或者同一个)list的某个定点 
    //将[first , last) 内的所有元素 移动到 position之前
    void transfer(iterator position,iterator first,iterator last){
        if (last != position){
            (*(link_type((*last.node).prev))).next = position.node; //1
            (*(link_type((*first.node).prev))).next = last.node;    //2
            (*(link_type((*position.node).prev))).next = first.node;//3
            link_type tmp = link_type ((*position.node).prev);      //4
            (*position.node).prev = (*last.node).prev;              //5
            (*last.node).prev = (*first.node).prev;                 //6
            (*first.node).prev = tmp;                               //7
        }
    }

  • 本质上是节点之间的指针移动,上述splice、reverse、sort函数本身依靠的是transfer函数

  •  完整代码  不一定对
#include <iostream>
#include <list>

template<class T,class Alloc>
class simple_alloc{
public:
    static T* allocate(std::size_t n){
        return 0==n?0:(T*)Alloc::allocate(n * sizeof(T));
    }
    static T* allocate(void){
        return (T*)Alloc::allocate(sizeof (T));
    }

    static void deallocate(T* p,size_t n){
        if (n!=0){
            Alloc::deallocate(p,n * sizeof(T));
        }
    }
    static void deallocate(T* p){
        Alloc::deallocate(p,sizeof(T));
    }
};


namespace Chy{
    template <class T>
    inline T* _allocate(ptrdiff_t size,T*){
        std::set_new_handler(0);
        T* tmp = (T*)(::operator new((std::size_t)(size * sizeof (T))));
        if (tmp == 0){
            std::cerr << "out of memory" << std::endl;
            exit(1);
        }
        return tmp;
    }

    template<class T>
    inline void _deallocate(T* buffer){
        ::operator delete (buffer);
    }

    template<class T1,class T2>
    inline void _construct(T1 *p,const T2& value){
        new(p) T1 (value);  //没看懂
    }

    template <class T>
    inline void _destroy(T* ptr){
        ptr->~T();
    }

    template <class T>
    class allocator{
    public:
        typedef T           value_type;
        typedef T*          pointer;
        typedef const T*    const_pointer;
        typedef T&          reference;
        typedef const T&    const_reference;
        typedef std::size_t size_type;
        typedef ptrdiff_t   difference_type;

        template<class U>
        struct rebind{
            typedef allocator<U>other;
        };

        pointer allocate(size_type n,const void * hint = 0){
            return _allocate((difference_type)n,(pointer)0);
        }

        void deallocate(pointer p,size_type n){
            _deallocate(p);
        }

        void construct(pointer p,const T& value){
            _construct(p,value);
        }

        void destroy(pointer p){
            _destroy(p);
        }

        pointer address(reference x){
            return (pointer)&x;
        }

        const_pointer const_address(const_reference x){
            return (const_pointer)&x;
        }

        size_type max_size()const{
            return size_type(UINT_MAX/sizeof (T));
        }
    };
}

//如果是copy construction 等同于assignment而且destructor 是 trivial以下就会有效
//如果是POD型别 执行的流程就会跳转到以下函数,这个是通过function template的参数推导机制得到的
template<class ForwardIterator,class Size,class T>
inline ForwardIterator __uninitizlized_fill_n_aux(ForwardIterator first,Size n,const T&x){
    return fill_n(first,n,x); //交给高阶函数执行
}

struct __true_type{};
struct __false_type{};

template<class T>
struct __type_traits {
    typedef __true_type this_dummy_member_must_be_first;
    typedef __false_type has_trivial_default_constructor;
    typedef __false_type has_trivial_copy_constructor;
    typedef __false_type has_trivial_assignment_constructor;
    typedef __false_type has_trivial_destructor;
    typedef __false_type is_POD_type;
};

//函数的逻辑是
//首先萃取出 迭代器first的value type,然后判断这个型别是否是POD类型
template<class ForwardIterator,class Size,class T,class T1>
inline ForwardIterator __uninitizlized_fill_n(ForwardIterator first,Size n,const T&x,T1*){
    //以下使用的是__type_traits<T1>::is_POD_type is _POD
    typedef typename __type_traits<T1>::is_POD_type is_POD;
    return __uninitizlized_fill_n_aux(first,n,x,is_POD());
}


template<class ForwardIterator,class Size,class T>
ForwardIterator uninitialized_fill_n(ForwardIterator first,Size n,const T&x){
    return __uninitizlized_fill_n(first,n,x,value_type(first));
    //使用value_type()判断first的value type
}

//list的节点结构设计
template <class T>
struct __list_node{
    typedef void* void_pointer;
    void_pointer prev;   //指针的类型是void*,其实可以将其设定为 __list_node<T>
    void_pointer next;
    T data;
};



//list的迭代器设计
template <class T,class Ref,class Ptr>
struct __list_iterator{
    typedef __list_iterator<T,T&,T*>    iterator;
    typedef __list_iterator<T,Ref,Ptr>  self;
    typedef std::bidirectional_iterator_tag iterator_category;
    typedef T value_type;
    typedef Ptr pointer;
    typedef Ref reference;
    typedef __list_node<T>* link_type;
    typedef std::size_t size_type;
    typedef ptrdiff_t difference_type;

    link_type node;//迭代器内部需要一个普通的指针,指向list节点

    //constructor
    __list_iterator(){}
    __list_iterator(link_type x):node(x){}
    __list_iterator(const iterator& x):node(x.node){}

    bool operator==(const self& x) const{return (node == x.node);}
    bool operator!=(const self& x) const{return (node != x.node);}

    //以下对迭代器取值 取得的是节点的数据值
    reference operator*() const {return (*node).data;}
    //以下是对迭代器的成员进行存取 (member access) 运算子的标准做法
    pointer operator->() const {return &(operator*());}

    //对迭代器进行加一 前进一个节点
    self& operator++(){
        node = (link_type)((*node).next);
    }

    self operator++(int){
        self tmp = *this;
        ++*this;
        return tmp;
    }

    //对迭代器进行减一 后退一个节点
    self& operator--(){
        node = (link_type)((*node).prev);
    }

    self operator--(int){
        self tmp = *this;
        --*this;
        return tmp;
    }

};

//list 环状双向链表设计如下
template <class T,class Alloc> //缺省使用alloc作为配置器
class list{

protected:
    typedef typename __list_iterator<T,T&,T*>::iterator iterator;
    typedef typename __list_iterator<T,T&,T*>::value_type value_type;
    typedef typename __list_iterator<T,T&,T*>::reference reference;
    typedef typename __list_iterator<T,T&,T*>::size_type size_type;

    typedef __list_node<T> list_node;
    //专属空间配置器 每次配置一个节点的大小
public:
    typedef list_node* link_type;
    typedef simple_alloc<list_node,Alloc>list_node_allocator;
    //list_node_allocator(n) 表示分配n个节点空间,以下四个函数分别用来配置、释放、构造、销毁一个节点
protected:
    //配置一个节点并返回
    link_type get_node(){return list_node_allocator::allocate();}
    //释放一个节点
    link_type put_node(){return list_node_allocator::deallocate();}
    //产生(配置并构造)一个节点 带有元素数值
    link_type create_node(const T& x){
        link_type p = get_node();
        Chy::allocator<T>::construct(p->data,x); //全局函数 构造/析构基本工具
        return p;
    }
    //销毁 (析构并释放) 一个节点
    void destroy_node(link_type p){
        Chy::allocator<T>::destroy(&p->data);  //全局函数 构造/析构基本工具
    }

public:
    //让指针node刻意指向尾端的一个空白节点,node节点便会符合STL对于前开后闭区间的要求,成为list迭代器
    iterator begin(){return (link_type)(*node->next);}
    iterator end(){return node;}
    bool empty()const{return node->next == node;}
    size_type size()const{
        size_type result = 0;
        std::distance(begin(),end(),result);
        return result;
    }
    //取头部节点的内容(元素数值)
    reference front(){
        return *begin();
    }
    //取尾节点的内容(元素数值)
    reference back(){
        return *(--end());
    }

    //插入元素 供push_back()函数调用
    //insert函数 需要配置并构造一个节点,然后在尾端进行指针操作,将新的节点插入进去
    //函数的目的是为了在迭代器指定的位置插入一个节点,内容为x
    iterator insert(iterator position,const T&x){ //产生一个节点,默认初始化元素数值为x
        link_type tmp = create_node(x);
        //调整双指针 将tmp插入进去
        tmp->next = position.node;
        tmp->prev = position.node->prev;
        (link_type(position.node->prev))->next = tmp;
        position.node->prev = tmp;
        return tmp;
    }

    //插入一个节点 作为头部节点
    void push_front(const T& x){
        insert(begin(),x);
    }

    //插入一个节点 作为尾节点
    void push_back(const T& x){
        insert(end(),x);
    }

    //移除迭代器position指向的节点
    iterator erase(iterator position){
        link_type next_node = link_type (position.node->next);
        link_type prev_node = link_type (position.node->prev);
        prev_node->next = next_node;
        next_node->prev = prev_node;
        destroy_node(position.node);
        return iterator (next_node);
    }

    //移除头部节点
    void pop_front(){
        erase(begin());
    }

    //移除尾部节点
    void pop_back(){
        iterator tmp = end();
        erase(--tmp);
    }

    //将[first , last) 内的所有元素 移动到 position之前
    void transfer(iterator position,iterator first,iterator last){
        if (last != position){
            (*(link_type((*last.node).prev))).next = position.node; //1
            (*(link_type((*first.node).prev))).next = last.node;    //2
            (*(link_type((*position.node).prev))).next = first.node;//3
            link_type tmp = link_type ((*position.node).prev);      //4
            (*position.node).prev = (*last.node).prev;              //5
            (*last.node).prev = (*first.node).prev;                 //6
            (*first.node).prev = tmp;                               //7
        }
    }





public:
    //构造函数
    //产生一个空的链表
    list(){empty_initialize();} //产生一个空的链表

    void clear();
    void remove(const T& value);
    void unique();


protected:
    link_type node; //只需要一个指针,便可以循环遍历整个环状的双向链表

    //空初始化
    void empty_initialize(){
        node = get_node();  //配置一个节点空间,令node指向它
        node->next = node;  //令node头尾指向自己  不设置元素值
        node->prev = node;
    }

public:
    //将x结合于position所指定位置之前 x必须不同于*this
    void splice(__list_iterator<T, T &, T *>, list &x);

    //将i指向的元素结合于position所指定的位置之前。position和i可以指向同一个list
    void splice(iterator position,list& ,iterator i){
        iterator j = i;
        ++j;
        if (position == i || position == j){
            return;
        }
        transfer(position,i,j);
    }

    //将[first,last)内的元素接合于position指定的位置之前
    //position 和 [first,last)内可能指向的是同一个list
    //但是position 不能位于 [first,last)内部
    void splice(iterator position,list &,iterator first,iterator last){
        if (first != last){
            transfer(position,first,last);
        }
    }

    //merage() 将x合并到*this身上,但是两个lists的内容都必须要先经过递增排序
    void meage(list& x){
        iterator first1 = begin();
        iterator last1  = end();
        iterator first2 = x.begin();
        iterator last2 = x.end();
        //两个list实现需要经过排序
        while (first1 != last1 && first2 != last2){
            if (*first2 < *first1){
                iterator next = first2;
                transfer(first1,first2,++next);
                first2 = next;
            } else{
                ++first1;
            }
            if (first2 != last2){
                transfer(last1,first2,last2);
            }
        }
    }

    //reverse() 将this的内容 逆向重置
    void reverse(){
        //以下判断,如果是空的链表,或者仅仅只有一个元素,就不进行任何的操作
        //使用size() == 0 || size() == 1 判断,速度较慢
        if (node->next == node ||link_type(node->next)->next == node)
            return;
        iterator first = begin();
        ++first;
        while (first != end()){
            iterator old = first;
            ++first;
            transfer(begin(),old,first);
        }
    }

    //list不能使用STL算法的sort() 因为STL算法只接受randomAccessIterator
    //本函数使用快速排序
    void sort(){
        //以下判断,如果是空的链表,或者仅仅只有一个元素,就不进行任何的操作
        //使用size() == 0 || size() == 1 判断,速度较慢
        if (node->next == node ||link_type(node->next)->next == node)
            return;
        //使用一些新的lists 作为中介数据存储区
        list carry;
        list counter[64];
        int fill = 0;
        while (!empty()){
            carry.splice(carry.begin(),*this,begin());
            int i = 0;
            while (i < fill && !counter[i].empty()){
                counter[i].merage(carry);
                carry.swap(counter[i++]);
            }
            carry.swap(counter[i]);
            if (i == fill){
                ++fill;
            }
        }
        for (int i = 1; i < fill; ++i) {
            counter[i].merage(counter[i-1]);
        }
        std::swap(counter[fill-1]);
    }
};


//清除所有的节点(整个链表)
template <class T,class Alloc>
void list<T,Alloc>::clear() {
    link_type cur = (link_type)node->next; //begin()
    while (cur != node){   //遍历每一个节点
        link_type tmp = cur;
        cur = (link_type)cur->next;
        destroy_node(tmp); //销毁、析构释放一个节点
    }
    //恢复node的原始状态
    node->next = node;
    node->prev = node;
}

//清除数值为value的所有元素
template<class T,class Alloc>
void list<T,Alloc>::remove(const T &value) {
    typedef typename __list_iterator<T,T&,T*>::iterator iterator;
    iterator first = __list_iterator<T,T&,T*>::begin();
    iterator last = __list_iterator<T,T&,T*>::end();
    while (first != last){
        iterator next = first;
        ++next;
        if (*first == value){
            __list_iterator<T,T&,T*>::erase(value);
            first = next;
        }
    }
}

//移除数值相同的连续元素,注意:只有"连续并且相同的元素",才会被删除只剩一个
template <class T,class Alloc>
void list<T,Alloc>::unique() {
    typedef typename __list_iterator<T,T&,T*>::iterator iterator;
    iterator first = __list_iterator<T,T&,T*>::begin();
    iterator last = __list_iterator<T,T&,T*>::end();
    if (first == last){
        return; //空的链表  什么都不做
    }
    iterator next = first;
    while(++next != last){       //遍历每一个节点
        if (*first == *next){    //如果这个区段中存在相同的元素
            __list_iterator<T,T&,T*>::erase(next); //移除之
        } else{
            first = next;        //调整指针
        }
        next = first;            //修正区段范围
    }
}

template <class T,class Alloc>
void list<T,Alloc>::splice(__list_iterator<T, T &, T *>position, list<T, Alloc> &x) {
    if (!x.empty()){
        transfer(position,x.begin(),x.end());
    }
}
  • 涉及到transfer的相关函数的代码 理解不是很透彻 垃圾
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值