std::stack 默认底层容器是 deque 而非 vector,因其头尾操作均为 O(1) 摊还复杂度;vector 虽内存紧凑但 pop 不释放内存,list 则缓存局部性差;使用时必须先检查 empty() 再调 top()/pop();不支持迭代器或下标访问;支持高效移动但拷贝代价高。

std::stack 默认用 deque 实现,不是 vector
很多人以为 std::stack 底层默认是 vector,其实标准规定它默认用 deque 作为底层容器。这是因为 deque 在头尾插入/删除都是 O(1)(摊还),而 vector 的 push_back 虽快,但若强制用 vector 做栈,pop 后内存不会自动收缩,且无法高效支持“模拟栈顶插入”之外的操作——不过 std::stack 本就不暴露迭代器,这点影响不大。
如果你想显式指定底层容器,可以这样写:
std::stack> s1; // 用 vector std::stack > s2; // 用 list(合法但不常用)
- 用
vector时,size()和内存占用更紧凑,但pop()不释放内存 - 用
list会失去缓存局部性,性能通常更差,一般没必要 - 除非有特殊需求(比如需要保证所有元素连续存储并手动管理内存),否则保持默认
deque即可
push / pop / top 三连操作必须配对检查 empty()
std::stack 不提供下标访问,也不允许遍历,只靠 top() 看栈顶、pop() 删栈顶、push() 加新元素。但 top() 和 pop() 都要求栈非空,否则行为未定义——不是抛异常,而是直接崩溃或读垃圾值。
常见错误写法:
立即学习“C++免费学习笔记(深入)”;
if (s.top() > 0) { // 错!没检查 empty()
s.pop();
}
正确做法永远是:
- 先调
s.empty(),再用s.top() -
pop()本身不返回值,想“取并删”,必须分两步:auto x = s.top(); s.pop(); - 别在循环条件里隐式调用
top(),例如while (!s.empty() && s.top() > 0)是安全的,但前提是empty()在前
stack 没有迭代器,遍历只能靠辅助容器或递归
这是初学者最常卡住的一点:std::stack 是容器适配器,接口被刻意阉割,不提供 begin()/end(),也没有 operator[]。如果你需要“打印全部元素”或“查找某个值”,不能直接遍历。
可行方案只有两个:
- 用临时容器中转:一边
pop()出去,一边存到vector或另一个stack,最后再倒回去(适合只读场景) - 改用底层容器本身:比如直接用
std::deque,然后用back()/pop_back()/push_back()模拟栈行为,这样就能用迭代器了 - 递归输出(仅限调试):写个辅助函数把栈倒腾进函数调用栈里,但深度大了会爆栈,生产代码禁用
没有“清空后保留原顺序”这种捷径;stack 的设计哲学就是「只关心栈顶」,其他都算越界需求。
移动语义支持良好,但拷贝代价高
std::stack 支持移动构造和移动赋值(C++11 起),底层容器如果是 deque 或 vector,移动几乎是 O(1)。但拷贝构造仍是深拷贝——整个底层容器全复制一份。
所以这些写法要注意:
- 函数参数尽量传
const std::stack,而不是值传递& - 返回局部
stack对象没问题,编译器会自动移动(NRVO 或移动返回) - 避免写
auto s2 = s1;这种无意义拷贝,除非你明确需要副本
真正容易被忽略的是:即使你只用 top() 和 size(),只要发生拷贝,底层 deque 的所有缓冲区都会被复制——这对大栈来说可能瞬间吃掉几 MB 内存。










