C++ 不同容器上的std::堆栈实现实际的区别是什么?

C++ 不同容器上的std::堆栈实现实际的区别是什么?,c++,stl,containers,stdstack,C++,Stl,Containers,Stdstack,实现std::stack 有几个选项,例如: // stack with default underlying deque std::stack< int > intDequeStack; // stack with underlying vector std::stack< int, std::vector< int > > intVectorStack; // stack with underlying list

实现
std::stack

有几个选项,例如:

   // stack with default underlying deque
   std::stack< int > intDequeStack;   

   // stack with underlying vector
   std::stack< int, std::vector< int > > intVectorStack;

   // stack with underlying list
   std::stack< int, std::list< int > > intListStack;
//具有默认基础数据的堆栈
std::stackintDequeStack;
//带底层向量的堆栈
std::stack>intVectorStack;
//与基础列表堆叠
std::stack>intListStack;
定义
std::stack
在不同的容器上,当我从它得到的只是相同的操作“推,弹出和顶部”


换句话说:deque堆栈与vector堆栈和list堆栈之间有什么区别?我为什么要选择deque以外的任何东西?

堆栈继承了底层容器的性能特征

  • std::vector
    对于最大大小不同的堆栈来说是一个糟糕的选择。堆栈上的每个
    推送
    ,都可能需要在向量中进行大量重新分配。向量也永远不会收缩,除非明确要求收缩,因此如果堆栈变大然后收缩,那么额外的内存将永远不会被释放(直到堆栈被销毁)。但是,向量与存储的数据之间只有一个间接层次

    因此:如果您知道堆栈将达到的最大大小,并且该大小相对较小,那么您调用的
    reserve()
    on2的向量在所有情况下都可能比list或deque更快;它具有非常好的数据局部性,并且访问元素的间接寻址级别减少了一级

  • std::list
    是一个链表,因此在弹出堆栈时,堆栈将具有两级间接寻址1,并且它将始终准确地使用它所需的内存量。推送上没有昂贵的重新分配,但它的数据局部性很差,因为每个节点都可以分配到堆中的任何位置;处理堆栈中的大量数据将无法有效地使用各种CPU内存缓存,因为每个pop可能需要跳转到堆中完全不同的位置

  • std::deque
    通过在一个结构(通常是一个链表)中维护一组短数组,将两者的某些方面结合起来。因此,项的集群将具有良好的数据局部性,并且结构可以按需增长和收缩,而不会有太大的麻烦,因为数组永远不会重新分配——如果它需要更多的空间,它将分配一个新数组并将其添加到结构的开始/结束处。它是向量和列表之间的一个很好的中间地带,这就是为什么它是默认值


1数据有一级间接寻址,但为了删除最后一个元素,链表需要另一级间接寻址到上一个节点以清除下一个指针

2请注意,在构造容器时需要移动向量。复制向量不一定能保持其容量。例如,您可以使用以下帮助器:

template <typename T>
std::stack<T, std::vector<T>> vector_stack(
    typename std::vector<T>::size_type capacity
) {
    std::vector<T> vec;
    vec.reserve(capacity);

    return std::stack<T, std::vector<T>>{std::move(vec)};
}
模板
std::堆栈向量\u堆栈(
typename std::vector::size\u类型容量
) {
std::vec;
车辆储备(容量);
返回std::stack{std::move(vec)};
}

您的前提有点不完整。一个
堆栈
有多个
推送
弹出
顶部
。例如,它有一个成员
c
,它是底层容器。它是受保护的,所以如果你喜欢,你可以随意摆弄它,忘记堆栈。向量、列表或deque在正常使用中的优势是什么?然后从堆栈的角度来思考。你让我好奇,我该如何处理它,我真的应该吗?