std::rotate 本质是循环左移,将 [first, middle) 与 [middle, last) 两段交换位置;middle 指向新序列首元素,非“转到开头”的偏移量,要求 first ≤ middle < last,直接修改原容器,C++20 起返回 last。

std::rotate 是怎么平移元素的
它不是“旋转数组”意义上的转圈,而是把迭代器范围 [first, last) 拆成两段:[first, middle) 和 [middle, last),然后把后一段挪到前面、前一段挪到后面——本质是循环左移 middle - first 个位置。比如 std::rotate(v.begin(), v.begin() + 2, v.end()) 把前两个元素移到末尾,不是让整个容器逆时针转一圈。
- 常见错误现象:
std::rotate后发现数据顺序“乱了”,其实是误以为 middle 指向要“转到开头”的那个值,实际 middle 是新序列的起始点(即原 middle 位置的元素会变成第一个) - 使用场景:实现 O(1) 空间复杂度的数组循环移位、滚动缓冲区更新、避免 vector 大量拷贝
- 参数差异:三个迭代器必须属于同一容器,且满足
first ≤ middle ≤ last,否则行为未定义;不接受整数偏移量,得自己算好middle
vector 和 list 上 std::rotate 的性能差别很大
std::rotate 对随机访问迭代器(如 vector、deque)用三步翻转法(reverse(reverse(A), reverse(B)), reverse(AB)),时间 O(n),空间 O(1);对双向迭代器(如 list)则直接链表指针重连,也是 O(n),但常数更小;对只读前向迭代器(如 forward_list)就只能靠移动元素,最坏 O(n²)。
- 容易踩的坑:在
forward_list上频繁调用std::rotate可能意外变慢,尤其 middle 靠后时;不如先转成 vector 再 rotate 再赋回(视数据规模而定) - 兼容性影响:C++11 起所有标准容器都支持,但注意
string_view没有迭代器可写,不能用 - 实操建议:若只是想循环左移 k 位,别手写三次 reverse,直接用
std::rotate(first, first + k, last)更清晰
std::rotate 改变的是容器内容,不是返回新容器
它直接修改原容器,返回 void(C++20 前),C++20 起返回 last 迭代器(方便链式调用),但不会生成副本。想保留原数据?得自己 auto backup = v;。
- 常见错误现象:对 const 容器或临时对象调用
std::rotate编译失败,因为需要非常量迭代器 - 使用场景:适合 inplace 更新,比如实时处理传感器数据流,每帧把最新样本推到开头,旧数据自动后移
- 参数陷阱:middle 不能等于 last(会导致空范围),也不能超出容器边界;调试时可加 assert(
middle >= first && middle )
替代方案:什么时候不该用 std::rotate
如果只是取某段子序列并拼接(比如 “abcde” → “deabc”),且不介意拷贝,用 insert + erase 更直白;如果要多次不同偏移量平移,预计算索引映射比反复 rotate 更快;如果容器很小(
立即学习“C++免费学习笔记(深入)”;
- 性能提示:gcc libstdc++ 在小范围上做了优化,但 clang libc++ 没统一策略,实测前建议 perf 对比
- 容易被忽略的地方:rotate 不保证异常安全——若元素移动构造抛异常,容器可能处于中间状态;含 noexcept 移动操作的类型才真正安全
- 实操底线:别为了“看起来高级”硬套
std::rotate,平移逻辑一目了然比代码短两行更重要











