手写链表栈因需暴露节点指针、支持遍历、定制内存分配或教学理解lifo本质;std::stack底层基于deque且不透明,无法访问中间节点。

为什么不用 std::stack 而要手写链表堆栈?
因为需要暴露节点指针、支持遍历、定制内存分配策略,或教学理解 LIFO 本质。标准库的 std::stack 默认基于 std::deque,底层不透明,也无法直接访问中间节点。
手写链表实现的关键是:每个节点只存数据 + 指向下一节点的指针;栈顶(top)始终是链表头;所有操作(push/pop/top)时间复杂度都是 O(1)。
push 和 pop 的指针操作必须小心哪几处?
常见错误是忘记更新 top 指针,或在 pop 后释放节点前访问已悬空的 top->next。C++ 中尤其要注意 new/delete 匹配和空栈边界。
-
push:新建节点 →new_node->next = top→top = new_node(顺序不能反,否则丢失原链) -
pop:先判空(if (!top) return)→ 保存旧top→top = top->next→ 再delete旧指针 - 不要写
top = top->next; delete top;——这会删掉新栈顶
构造函数、析构函数和拷贝控制怎么写才安全?
链表堆栈涉及裸指针,必须显式定义析构函数清空整个链;否则对象销毁时只释放栈对象本身,节点内存泄漏。拷贝构造和赋值运算符若不自定义,默认逐成员复制指针,导致两个栈共享同一链表,后续析构会 double-free。
最小可行实现示例:
struct StackNode {
int data;
StackNode* next;
StackNode(int d) : data(d), next(nullptr) {}
};
<p>class LinkedStack {
StackNode<em> top;
public:
LinkedStack() : top(nullptr) {}
~LinkedStack() {
while (top) {
StackNode</em> tmp = top;
top = top->next;
delete tmp;
}
}
void push(int x) {
StackNode<em> n = new StackNode(x);
n->next = top;
top = n;
}
void pop() {
if (!top) return;
StackNode</em> tmp = top;
top = top->next;
delete tmp;
}
int topValue() const {
return top ? top->data : throw std::runtime_error("empty stack");
}
};</p>
用智能指针能省事吗?要注意什么?
能,但别无脑换 std::unique_ptr。把 top 改成 std::unique_ptr<stacknode></stacknode> 后,push 要用 std::make_unique,pop 只需 top = std::move(top->next)——自动释放原节点。
但注意:topValue() 返回 top->data 没问题;若想返回引用(如 int&),必须确保节点生命周期由栈完全管理,且调用方不会在栈修改后继续使用该引用。
真正容易被忽略的是异常安全:如果 new 或构造 StackNode 抛异常,原始链表不能损坏。裸指针版本做不到这点;而 std::unique_ptr 在构造中途异常时会自动清理已分配节点,更稳妥。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











