deque的push_front()和push_back()分别在首尾插入元素,时间复杂度均摊O(1),不导致迭代器失效;需注意pop前判空,且不可用erase替代pop操作。

deque 的 push_front 和 push_back 怎么用
直接调用 push_front() 和 push_back() 就能往两端插入元素,底层自动处理内存扩展,不用手动管理。这两个操作都是均摊 O(1) 时间复杂度,但注意:每次扩容可能触发整块内存复制,所以高频小量插入比预分配好,而一次性插大量建议先 reserve()(虽然 deque 不支持 reserve(),这点和 vector 不同——它靠分段缓冲区管理,不能像 vector 那样提前预留连续空间)。
常见错误是误以为 push_front(0) 会让后续所有下标偏移 +1,其实不会影响已有迭代器的合法性(deque 迭代器在插入时不失效,这是它和 vector 的关键区别之一)。
-
push_front(x):插到最前面,新元素索引变为 0 -
push_back(x):插到最后面,新元素索引为size()-1 - 插入后
front()和back()会立即反映新值
pop_front 和 pop_back 为什么不能用 [] 访问后直接 erase
别写 v.erase(v.begin()) 或 v.erase(v.end()-1) 来模拟出队——虽然语法合法,但效率低且违背设计意图。deque 的 erase() 对首尾操作不是 O(1),而是 O(min(pos, size()-pos)),因为内部要调整缓冲区指针;而 pop_front() 和 pop_back() 是真正 O(1) 的原生操作。
更危险的是:如果 deque 当前只有一个元素,调用 pop_back() 后再访问 front() 会未定义行为(UB),必须检查 empty()。
立即学习“C++免费学习笔记(深入)”;
- 永远优先用
pop_front()/pop_back(),而非erase() - 出队前务必判断
if (!dq.empty()),否则front()、back()、pop_*全都 UB -
pop_*不返回值,要取值再删,得先auto x = dq.front(); dq.pop_front();
迭代器失效规则和 vector 有什么不同
deque 的迭代器在首尾插入/删除时不会失效,这是它被选作双端队列的核心优势。但中间位置的 insert() 或 erase() 会导致所有迭代器失效(和 vector 一样)。另外,虽然迭代器不因首尾操作失效,但引用和指针仍可能失效——因为 deque 内部是分段堆分配,元素不一定在连续内存中。
- 安全场景:用
auto it = dq.begin(); push_front(); *it依然有效 - 不安全场景:用
int* p = &dq[0]; pop_front(); *p可能访问野地址 - 跨段访问无性能惩罚,但
operator[]比vector略慢(需计算段号+段内偏移)
为什么 size() 很快但遍历局部性差
deque::size() 是 O(1),因为它缓存了大小;但顺序遍历比 vector 慢,因为每个缓冲区段独立分配,CPU 缓存预取容易失败。实测百万级数据遍历时,deque 常比 vector 慢 2–3 倍。
如果你只是需要双端进出,但大部分时间在遍历或随机访问,先确认是否真需要 deque——很多场景用 vector + 两个索引(头尾游标)模拟循环队列,或者干脆用 std::queue(默认适配器就是 deque)更稳妥。
- 高频随机访问 → 优先
vector或array - 频繁首尾增删 + 中等规模数据 →
deque合理 - 极端性能敏感且只用首尾 → 考虑自实现 ring buffer(避免分配器开销)
实际用的时候,最容易被忽略的是:deque 的内存布局不可预测,任何基于“地址连续”做的假设(比如 memcpy、reinterpret_cast 成数组)都会崩溃。


















