std::queue更安全,手写指针队列仅用于裸机/嵌入式、教学或需精确控制内存布局、规避stl分配器开销等特殊场景,但须自行处理空指针、内存泄漏、线程竞争等风险。

为什么不用 std::queue 而要手写指针队列?
除非在裸机、嵌入式受限环境,或教学场景明确要求理解链式结构原理,否则直接用 std::queue 更安全。手写指针队列的主要动机通常是:需要精确控制内存布局、避免 STL 分配器开销、或调试底层数据流动。一旦决定手写,就必须自己处理空指针解引用、内存泄漏、多线程竞争等风险。
Node 结构体和 Queue 类的基本定义
链式队列的核心是单向链表节点 + 两个指针(front 和 rear)。关键点在于:节点构造函数必须初始化 next 为 nullptr;队列类的 front 和 rear 初始值都应为 nullptr,而非任意地址。
常见错误是忘记初始化 next,导致后续 rear->next = new_node 写入随机地址:
struct Node {
int data;
Node* next;
Node(int d) : data(d), next(nullptr) {} // 必须显式设 next 为 nullptr
};
<p>class Queue {
private:
Node<em> front;
Node</em> rear;
public:
Queue() : front(nullptr), rear(nullptr) {}
};</p>
enqueue 和 dequeue 的边界处理
插入(enqueue)时,若队列为空,front 和 rear 都要指向新节点;否则只更新 rear->next 和 rear。删除(dequeue)时,若删完后队列变空,必须把 front 和 rear 同时置为 nullptr,否则 rear 会悬空。
-
enqueue前不检查new Node是否返回nullptr→ 可能崩溃(尤其在嵌入式无异常环境中) -
dequeue后未置空rear→ 下次enqueue时rear->next解引用非法地址 - 未在
dequeue返回前保存front指针 → 删除后无法读取数据
正确写法片段:
void enqueue(int val) {
Node* newNode = new Node(val);
if (!newNode) return; // 内存分配失败
if (!rear) {
front = rear = newNode;
} else {
rear->next = newNode;
rear = newNode;
}
}
<p>int dequeue() {
if (!front) throw std::runtime_error("queue is empty");
Node* oldFront = front;
int val = oldFront->data;
front = front->next;
if (!front) rear = nullptr; // 关键:队列变空时 rear 必须置空
delete oldFront;
return val;
}</p>
析构函数里漏掉遍历释放会导致内存泄漏
Queue 析构函数不能只删 front 或只删 rear。必须从 front 开始逐个释放,且每次释放前保存下一个节点指针 —— 否则释放后就无法访问 next。
典型错误写法:delete front; → 接着访问 front->next 就是野指针。
安全做法:
~Queue() {
while (front) {
Node* temp = front;
front = front->next;
delete temp;
}
rear = nullptr; // 避免悬挂
}
如果队列生命周期长、操作频繁,还要考虑拷贝构造和赋值运算符是否禁用(通常应删除或实现深拷贝),否则浅拷贝会导致双删。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











