最安全的选择是直接使用 std::swap,它已针对内置类型、STL容器和自定义类高度优化,支持移动语义、异常安全与自赋值处理,且需包含头文件。

直接用 std::swap 最安全,别自己造轮子
绝大多数场景下,std::swap 是唯一推荐的选择。它已针对内置类型、STL 容器、自定义类(有移动语义)做了高度优化,且能正确处理引用、const 限定、异常安全等边界情况。手写交换逻辑不仅没必要,还容易出错。
常见错误现象:自己实现时忽略类型大小、对齐、或未处理自赋值(a = b; b = a; 在 a 和 b 是同一变量时会出错)。
- 使用前需包含头文件:
#include(C++11 起) - 支持任意可移动/可复制类型:
std::swap(vec1, vec2)是 O(1) 的指针交换,不是逐元素拷贝 - 对内置类型(如
int),编译器通常内联为几条寄存器指令,性能不输位运算
位运算交换(x ^= y; y ^= x; x ^= y;)只适用于整型且不能有别名
这个技巧在 C 语言老教程里常见,但在 C++ 中基本没有实用价值,反而隐患明显。
典型错误现象:对浮点数、指针、用户自定义类型编译失败;对同一变量调用(如 swap(a, a))导致值变 0;在含副作用的表达式中行为未定义(如 swap(*p++, *q))。
立即学习“C++免费学习笔记(深入)”;
- 仅对无符号/有符号整型(
int,unsigned long等)语法合法 - 必须确保两个操作数不指向同一内存地址,否则结果为 0 —— 这无法在编译期检查
- 现代 CPU 流水线对这种序列并不友好,实际性能常不如三条 mov 指令
int a = 5, b = 8; a ^= b; // a = 5 ^ 8 b ^= a; // b = 8 ^ (5 ^ 8) = 5 a ^= b; // a = (5 ^ 8) ^ 5 = 8 → 成功,但仅限此干净场景
自定义 swap 函数时,必须特化或重载,不能简单模板推导
如果你的类需要高效交换(比如管理动态内存),应提供自定义 swap,但必须走标准约定路径,否则 std::swap 不会自动调用它。
常见错误现象:写了 void my_swap(MyClass& a, MyClass& b),但 std::swap(a, b) 仍调用默认版本,没触发你的逻辑。
- 正确做法是:在类所在命名空间内定义非成员函数
void swap(MyClass& a, MyClass& b)(非模板) - 或对
std::swap进行全特化(需在std::命名空间内,且仅限针对用户定义类型) - C++20 起可借助
friend void swap(...)在类内声明,更简洁安全
引用交换(int& a_ref = a; int& b_ref = b;)根本不能交换变量本身
这是初学者高频误解:以为通过引用来“交换引用目标”,就能改变原变量绑定关系。但 C++ 中引用一旦初始化,就不能再绑定到其他对象。
错误代码示例:int& temp = a; a = b; b = temp; —— 这只是拷贝值,不是交换引用。
- 引用不是指针,没有“重新赋值”操作符
- 想间接操作变量,应该用指针(
int* p = &a;),但依然要靠赋值完成数据交换,而非改变指针本身的意义 - 真正需要运行时切换绑定的场景,应考虑
std::reference_wrapper或智能指针
真正复杂的地方在于:你以为在交换“变量”,其实是在交换“值”“资源”或“所有权”。std::swap 的强大,恰恰来自它对这三者的自动区分——你不需要知道 vector 内部是指针还是小缓冲区,它都给你最优解。手写任何替代方案,第一步就得先回答:“我到底想交换什么?”










