std::swap 可安全高效交换 std::array(o(1),类型与长度必须一致),但对原生数组无效;后者应使用 std::swap_ranges(需等长、pod、对齐)或重构为容器。

用 std::swap 直接交换数组对象(C++11 及以上)
如果两个数组是 std::array 或封装在容器里,std::swap 是最安全、最高效的选择——它不复制元素,只交换内部指针或元数据。
常见错误是手动循环赋值,或误以为 std::swap 对原生数组有效。注意:std::swap 对原生数组(如 int arr[10])默认不生效,因为数组类型不可赋值;必须用 std::array 或容器包装。
-
std::array大小在编译期固定,交换开销是 O(1),底层通常只交换三个字(大小 + 指针/内联存储标记) - 确保两个
std::array类型完全一致:元素类型和长度都必须相同,否则编译失败 - 示例:
std::array<int> a = {1,2,3,4,5};<br>std::array<int> b = {6,7,8,9,0};<br>std::swap(a, b); // ✅ 立即完成,无拷贝</int></int>
原生数组只能逐元素交换或用 std::swap_ranges
对于 int arr1[1000] 这类 C 风格数组,没有“整体交换”的语言机制。强行用 memcpy + 临时缓冲会多一次内存分配和两次拷贝,反而更慢。
推荐用 std::swap_ranges,它底层通常展开为汇编级的寄存器交换(尤其对 POD 类型),避免中间临时变量,且可被编译器充分优化。
- 必须确保两段内存长度相等,否则行为未定义;建议配合
sizeof或 constexpr 长度校验 - 不能用于含非平凡构造/析构函数的对象(如
std::string数组),此时需用std::swap逐个调用 - 示例:
int a[3] = {1,2,3};<br>int b[3] = {4,5,6};<br>std::swap_ranges(std::begin(a), std::end(a), std::begin(b));
避免踩坑:别用 std::vector::swap 混淆语义
std::vector::swap 确实是 O(1),但它交换的是整个 vector 对象的控制块(指针、size、capacity),不是“数组内容”。如果你本意是交换两个 vector 的底层数据,这没问题;但若目标是交换两个独立堆内存块的内容(比如两个 new int[N]),那就完全错了。
- 对裸指针数组,
std::vector::swap不适用,也没法直接套用 - 误写成
v1.swap(v2)却忘了 v1 和 v2 是不同 size,会导致后续访问越界,但编译器不会报错 - 真正需要交换裸指针指向的数据时,要么用
std::swap_ranges,要么用std::iter_swap配合循环(仅当数量极小时)
性能关键点:对齐与类型决定是否可向量化
现代编译器(GCC/Clang/MSVC)对 std::swap_ranges 或手写循环的优化程度,高度依赖元素类型和内存对齐。例如 int 数组在 16 字节对齐时,很可能生成 AVX2 的 vpxor 三指令交换序列;但 char 数组或未对齐地址,就退化为逐字节操作。
- 用
alignas强制对齐能提升交换速度,尤其对大数组:alignas(32) int a[1024];
- 自定义结构体交换前,确认其满足 trivially copyable,否则
std::swap_ranges行为未定义 - 调试时可加
-O2 -fopt-info-vec(GCC)看是否向量化成功;若提示 “loop not vectorized: data dependencies”,说明有别名问题,需加restrict或改用std::array
std::array —— 是就直接 std::swap;不是就检查是否 POD、是否对齐、是否等长,再决定用 swap_ranges 还是重构成容器。最容易被忽略的是原生数组类型擦除后丢失长度信息,导致 std::end 无法推导,必须显式传入迭代器范围。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











