序列式容器

Posted ccpang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了序列式容器相关的知识,希望对你有一定的参考价值。

容器结构分类

这里的衍生,并非继承关系,而是一种包含关系。
例如heap中包含一个vector。

技术图片

通过萃取机traits萃取迭代器的型别

template <class I>
struct iterator_traits { //traits是特性之意
    typedef typename I::value_type value_type;
};
//两个偏特化(partial specialization)
template <class T>
struct iterator_traits<T*> {
    typedef T value_type;
};
template <class T>
struct iterator_traits<const T*> {
    typedef T value_type; //注意是T而不是const T,因为value_type的主要目的是用来声明变量,而声明一个无法被赋值的变量是没有什么用的(const T),所以要去掉const
};
//于是当需要知道I的value_type时,便可以这么写:
template<typename I>
void algorithm(...) {
    typename iterator_traits<I>::value_type v1;
}

容器list

list在要内存时,不光需要一个指针,还需要指向前后的两个指针。
技术图片

list的定义

//list的定义
    template<class T, class Alloc = alloc>
    class list {
    protected:
        typedef __list_node<T> list_node;
    public:
        typedef list_node* link_type;
        //G2.9编译器的iterator
        typedef __list_iterator<T, T&, T*> iterator;
        //G4.9编译器的iterator
        typedef _List_iterator<_Tp> iterator;
    portected:
        link_type node;
    };

list的node定义

G2.9编译器的设计是如下所示:其中前向指针和后向指针,指向的都是void类型,所以sizeof(list)是4个字节,就是一个指向数据的指针。

//list节点的定义
    template <class T>
    struct __list_node {
        typedef void* void_pointer;
        void_pointer prev;
        void_pointer next;
        T data;
    };

G4.9版本在G2.9版本的基础之上,将node部分拆分成了两个部分,一个是_list_node_base,改变了G2.9版本的前向和后向指针的指向类型,另外node是继承_List_node_base后,再加上数据部分,如下所示:

//G4.9编译器,list节点的定义:
    struct _List_node_base {
        _List_node_base* _M_next;
        _List_node_base* _M_prev;
    };
    template<typename _Tp>
    struct _List_node : public _List_node_base {
        _Tp _M_data;
    };

list的iterator

list的存储是非连续空间,所以list的iterator不能是普通指针。而是定义一个class来模拟指针,称之为smart pointer

技术图片
如上图红色的泡泡,当list的iterator加一时,应该指向下一个节点的位置。所以list的iterator是一个smart pointer.
每个iterator要有5个typedef,因为迭代器是容器和算法之间的桥梁,所以迭代器必须定义这五种typedef,以便于回答算法的提问:
传入类型T的参数,直接T::iterator_category,就可以得到迭代器的类型。

  • iterator_category
  • value_type
  • difference_type
  • pointer
  • reference
    list的五个reference如下所示:
//list的五个typedef定义
template<typename _TP>
struct _List_iterator {
    typedef std::bidirectional_iterator_tag iterator_category;
    typedef _Tp value_type;
    typedef _Tp* pointer;
    typedef _Tp& reference;
    typedef ptrdiff_t difference_type;
};

还有一大堆的操作符重载。

//list的iterator的定义
    template <typename _Tp>
    struct _List_iterator {
        typedef _Tp* poinetr;
        typedef _Tp& reference;
    };

容器vector

vector的扩充方式是两倍增长,换一个内存后进行两倍增长。

vector的定义

//vector的定义
template <class T,class Alloc = alloc>
class vector{
public:
    typedef T value_type;
    typedef value_type* iterator;//T*
    typedef value_type& reference;
    typedef size_t size_type;
protected:
    iterator start;
    iterator finish;
    iterator end_of_storage;
public:
    iterator begin() { return start; }
    iterator end() { return finish; }
    size_type size() const { //大小 finish-start
        return size_type(end() - begin());
    }
    size_type capacity() const { //容量
        return size_type(end_of_storage - begin());
    }
    bool empty() const { return begin() == end(); }
    reference operator[](size_type n) { //连续空间的中括号
        return *(begin() + n);
    }
    reference front() { return *begin(); } //取出首个元素
    reference back() { //取出尾部元素
        return *(end() - 1);
    }
}

vector的iterator

//vector的迭代器设计
template <class T, class Alloc = alloc>
class vector {
public:
    typedef T value_type;
    typedef value_type* iterator; //T*
};
vector<int>vec;
vector<int>::iterator ite = vec.begin();

vector 的大小

vector的大小是三个指针,start,finish,end_of_storage,这三个指针的大小是12.

array

array的定义

//array的定义
template <typename _Tp, std::size_t _Nm>
struct array{
    typedef _Tp value_type;
    typedef _Tp* pointer;
    typedef value_type* iterator;

    //支持0大小的数组生成
    value_type _M_instance[_Nm ? _Nm : 1];

    iterator begin() {
        return iterator(&_M_instance[0]);
    }
    iterator end() {  //最后一个元素的下一个元素
        return iterator(&_M_instance[_Nm]);
    }
};

forward_list

forward_list与list的区别

单向链表与list的区别仅仅只在于一个是单向,一个是双向,其他都是相同的。

deque

deque是一个双向开口的连续线性空间,其实是动态的以分段连续空间组合而成 ,外界以为它是连续的。
技术图片

deque是由一段一段定量的连续空间构成,一旦有必要在deque的前端或后端增加新空间时,便配置一段定量的连续空间,串接在整个deque的头端或尾端,deque的最大任务就是在这些分段的定量连续空间上,维护其整体连续的假象,并提供随机存取的接口,避开了“重新配置、复制、释放”的轮回,代价则是复杂的迭代器架构。

如上图所示,deque管理一个map(一小块连续空间),map是一个vector,其中每个元素是一个指针,指向另一段较大的连续线性空间,称为缓冲区。

deque的定义

//一个deque的大小是40个字节

template <class T,class Alloc = alloc, size_t BufSiz = 0> //BufSizs是buffer的大小
class deque {
public:
    typedef T value_type;
    typedef __deque_iterator<T, T&, T*, BufSiz>iterator;
protected:
    typedef pointer* map_pointer; //T**
protected:
    iterator start; //大小是16个字节
    iterator finish; //大小是16个字节
    map_pointer map; //控制中心是个vector,是会2倍动态增长的 T** 指向指针的指针 大小是4
    size_type map_size; //大小是4字节
public:
    iterator begin() { return start; }
    iterator end() { return finish; }
    iterator size() const { return finish - start; }
};

deque的iterator

deque的迭代器包含四个部分:cur first last node

//deque的iterator
template <class T, class Ref, class Ptr,size_t BufSiz>
struct __deque_iterator {
    typedef random_access_iterator_tag  iterator_category;
    typedef T value_type;
    typedef Ptr pointer;
    typedef Ref reference;
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;
    typedef T** map_pointer;
    typedef __deque_iterator self;

    T* cur;
    T* first;
    T* last;
    map_pointer node;

};

以上是关于序列式容器的主要内容,如果未能解决你的问题,请参考以下文章

C++迭代器失效的几种情况总结

序列式容器

❤️ STL 序列式容器 vector 超硬核源码剖析 ❤️

STL序列式容器之list

序列式容器————vector

序列式容器————queue