std::rotate是移动连续子段的最优解,时间复杂度O(n)且原地完成;错误做法包括手写循环、insert+erase或std::copy,易越界、性能差或引发未定义行为。

用 std::rotate 移动连续子段最直接
想把 vec[a..b) 这段元素整体挪到位置 c(比如插到某处前面),std::rotate 是标准库中唯一专为此设计的算法,时间复杂度 O(n),且原地完成、不额外分配内存。
常见错误是手写循环或用 insert+erase —— 前者易越界、后者触发多次移动,性能差一个数量级。
- 若要把
[first, middle)移到middle之后(即“后移”),调用std::rotate(first, middle, last) - 若要“前移”,比如把
[middle, last)挪到first前面,同样用std::rotate(first, middle, last)—— rotate 本质是三段轮换,方向由迭代器顺序决定 - 务必确保迭代器合法:
first ≤ middle ≤ last,否则行为未定义
std::move + insert 适合小段或需保留原数据
当你要把一段元素“复制并插入”到别处(原位置还留着),或者移动距离很短(比如只挪 1–2 个位置),std::move 配合 insert 更直观,但注意:它会引发后续元素批量平移,复杂度 O(n×移动距离)。
典型场景:把最后几个元素提到开头,且原 vector 不能破坏。
立即学习“C++免费学习笔记(深入)”;
- 先用
std::move(vec.begin() + a, vec.begin() + b, std::back_inserter(temp))搬到临时容器(如果需要保留) - 或直接
vec.insert(vec.begin() + c, std::make_move_iterator(vec.begin() + a), std::make_move_iterator(vec.begin() + b)) - 之后再
vec.erase(vec.begin() + a + (c > a ? (b - a) : 0), vec.begin() + b + (c > a ? (b - a) : 0))—— 这里偏移计算极易出错,建议分步调试
避免用 std::copy 或裸循环手动搬
手写 for 循环拷贝元素看似可控,但实际踩坑密集:迭代器失效、自赋值崩溃、移动语义丢失、边界错一位就全乱。
比如 for (int i = a; i —— 当 <code>c 时,<code>vec[i] 可能已被覆盖,数据损坏。
- 除非你明确知道源区间和目标区间完全不重叠,且类型支持 trivial move,否则别碰裸循环
-
std::copy默认是 copy 而非 move,对大对象浪费深拷贝开销 - 即使加
std::move_iterator,也绕不开重叠区间判断,不如交给std::rotate
移动后迭代器和引用全部失效
无论用哪种方式移动元素,只要 vector 内部发生元素重排(包括 rotate),所有指向该 vector 元素的迭代器、指针、引用立即失效。这点常被忽略,尤其在循环中边遍历边移动。
- 如果依赖某个
auto it = vec.begin() + x后还要移动元素,必须在移动前保存索引(如size_t pos = it - vec.begin()),移动后再重新计算 - lambda 捕获的引用变量也会悬空,需改用值捕获或延迟访问
-
reserve不能防止移动导致的失效——它只防扩容,不防内部重排
真正高效的前提,是承认“移动即重构布局”,别试图在移动过程中维持旧视图。


















