C++源码剖析——序列容器适配器(stack,queue,priority_queue)

  前言:之前看过侯老师的《STL源码剖析》但是那已经是多年以前的,现在工作中有时候查问题和崩溃都需要了解实际工作中使用到的STL的实现。因此计划把STL的源码再过一遍。
  摘要:本文描述了llvm中libcxx的allocator的实现。
  关键字stack,queue,priority_queue
  其他:参考代码LLVM-libcxx
  注意:参考代码时llvm的实现,与gnu和msvc的实现都有区别。文章假设你已经非常熟悉数据结构,并不会对对应的数据结构细节进行深究。

  C++中有三种常用的容器,本身并不是一个容器而是适配器,即其实际的利用已有的容器实现的对应容器的功能。

  • stack提供了FILO(先入后出)的能力。
  • queue提供了FIFO的能力。
  • priority_queue优先队列。

1 stack

  stack在STL中的实现默认是通过deque,当然也可以指定容器,但是前提是对应的容器包含某些操作接口。说stack是适配器也可以看到,该类里面就是包装了另一个容器,然后利用该容器的接口实现需要的功能。如果期望使用自定义的容器,对应的容器应该支持pop_back(), push_back(), size(), empty()等接口。

template <class _Tp, class _Container /*= deque<_Tp>*/>
class _LIBCPP_TEMPLATE_VIS stack{
    
    
public:
    typedef _Container                               container_type;
    typedef typename container_type::value_type      value_type;
    typedef typename container_type::reference       reference;
    typedef typename container_type::const_reference const_reference;
    typedef typename container_type::size_type       size_type;
    static_assert((is_same<_Tp, value_type>::value), "" );

protected:
    container_type c;
};

  stack的实现比较简单,没什么好说的。需要注意的是toppop分开实现了而不是直接一个接口实现是为了保证异常安全。如果在同一个接口中实现,当获取元素时正常,pop完数据,返回过程中拷贝数据对象时发生异常数据就会丢失。

void push(const value_type& __v) {
    
    c.push_back(__v);}
const_reference top() const {
    
    return c.back();}
void pop() {
    
    c.pop_back();}

2 queue

  queuestack定义相同默认都是包装了一个deque

template <class _Tp, class _Container /*= deque<_Tp>*/>
class _LIBCPP_TEMPLATE_VIS queue{
    
    
public:
    typedef _Container                               container_type;
    typedef typename container_type::value_type      value_type;
    typedef typename container_type::reference       reference;
    typedef typename container_type::const_reference const_reference;
    typedef typename container_type::size_type       size_type;
    static_assert((is_same<_Tp, value_type>::value), "" );

protected:
    container_type c;
};

  deque的实现也非常简单,不多描述。

    bool      empty() const {
    
    return c.empty();}
    _LIBCPP_INLINE_VISIBILITY
    size_type size() const  {
    
    return c.size();}

    _LIBCPP_INLINE_VISIBILITY
    reference       front()       {
    
    return c.front();}
    _LIBCPP_INLINE_VISIBILITY
    const_reference front() const {
    
    return c.front();}
    _LIBCPP_INLINE_VISIBILITY
    reference       back()        {
    
    return c.back();}
    _LIBCPP_INLINE_VISIBILITY
    const_reference back() const  {
    
    return c.back();}

    _LIBCPP_INLINE_VISIBILITY
    void push(const value_type& __v) {
    
    c.push_back(__v);}

3 priority_queue

  优先队列就是一个堆,容器内数据某种程度上是有序的。优先队列的实现和前两者有些差别,默认是vector,因为容器内元素是某种程度上有序的,所以需要提供比较函数。

template <class _Tp, class _Container = vector<_Tp>, class _Compare = less<typename _Container::value_type> >
class _LIBCPP_TEMPLATE_VIS priority_queue{
    
    
public:
    typedef _Container                               container_type;
    typedef _Compare                                 value_compare;
    typedef typename container_type::value_type      value_type;
    typedef typename container_type::reference       reference;
    typedef typename container_type::const_reference const_reference;
    typedef typename container_type::size_type       size_type;
    static_assert((is_same<_Tp, value_type>::value), "" );

protected:
    container_type c;
    value_compare comp;
};

  在构造堆时会调用std::make_heap在当前容器上创建堆。现在不详细具体的实现,等看算法实现时再详细描述(估计是一般的堆构造算法)。

template <class _Tp, class _Container, class _Compare>
inline priority_queue<_Tp, _Container, _Compare>::priority_queue(const value_compare& __comp, container_type&& __c)
    : c(_VSTD::move(__c)),
      comp(__comp){
    
    
    _VSTD::make_heap(c.begin(), c.end(), comp);
}

  插入和弹出元素也都调用的是std的算法实现。

template <class _Tp, class _Container, class _Compare>
inline void priority_queue<_Tp, _Container, _Compare>::push(value_type&& __v){
    
    
    c.push_back(_VSTD::move(__v));
    _VSTD::push_heap(c.begin(), c.end(), comp);
}

template <class _Tp, class _Container, class _Compare>
inline void priority_queue<_Tp, _Container, _Compare>::pop(){
    
    
    _VSTD::pop_heap(c.begin(), c.end(), comp);
    c.pop_back();
}

猜你喜欢

转载自blog.csdn.net/GrayOnDream/article/details/129918753