std::swap是C++标准库中高效交换对象值的函数,定义在中,优先使用移动语义或位交换,避免深拷贝;直接赋值会导致数据丢失,手写临时变量冗余且不通用。

std::swap 是什么,为什么不能直接用赋值
std::swap 是 C++ 标准库中用于交换两个对象值的函数,定义在 头文件里。它不是简单的三行赋值(临时变量 + a=b + b=临时),而是针对不同类型做了优化:对基础类型是位交换,对类类型会优先调用移动语义(如果可用),避免深拷贝开销。
直接写 a = b; b = a; 会导致 b 值丢失,这是初学者常见错误;而手写临时变量虽然可行,但冗余、易错,且无法自动适配自定义类型或容器。
基本用法:交换 int、double、string 等内置/标准类型
只要类型支持移动构造/赋值或拷贝构造/赋值,std::swap 就能用。注意必须显式包含头文件,否则编译报错 ‘swap’ was not declared in this scope。
- 不加
using std::swap;时,必须写全名std::swap(a, b) - 对
std::array、std::vector等容器,std::swap会交换内部指针(O(1) 时间),而不是逐个元素复制 - 交换
const对象?不行 ——std::swap参数是左值引用,要求可修改
#include#include int main() { int a = 10, b = 20; std::swap(a, b); // ✅ 安全、高效 std::cout << a << " " << b << "\n"; // 输出: 20 10 }
自定义类怎么让 swap 更快:提供非成员 swap 重载
如果你的类管理动态资源(比如自己 new 的数组),默认的 std::swap 会触发拷贝构造 + 拷贝赋值,性能差还可能抛异常。正确做法是在类所在命名空间中定义非成员 swap 函数,并声明为 friend 或公有接口。
立即学习“C++免费学习笔记(深入)”;
- 不要在
std命名空间里加东西(违反标准,未定义行为) - ADL(参数依赖查找)会让
std::swap(x, y)自动找到你定义的swap(MyClass&, MyClass&) - 函数体内应只做成员交换(用
std::swap递归交换各字段),不分配新资源
struct Widget {
int* data;
Widget(int x) : data(new int(x)) {}
~Widget() { delete data; }
// ... 拷贝/移动操作略
};
// 在 Widget 同一命名空间(全局)中定义
void swap(Widget& a, Widget& b) noexcept {
std::swap(a.data, b.data); // 仅交换指针
}
常见陷阱:std::swap 与 ADL 冲突、右值引用误用
最隐蔽的问题是:你写了自定义 swap,但调用时没触发,还是走默认拷贝版。原因常是忘记 ADL 触发条件 —— 比如用了 using std::swap; 后又写 swap(a, b),编译器可能只找 std::swap 而忽略你的版本。
- 安全写法:始终用
using std::swap; swap(a, b);(两行),靠 ADL 找到最优重载 - 别对字面量或临时对象调用
std::swap:例如std::swap(1, x)编译失败(无法绑定非常量左值引用) - 容器的
swap成员函数(如v1.swap(v2))和std::swap(v1, v2)等价,但前者更明确,某些老编译器对后者 ADL 支持弱
真正复杂的地方在于:当类模板嵌套、继承关系存在时,swap 重载要覆盖所有可能组合,稍有遗漏就退化成低效拷贝 —— 这点很容易被忽略,直到压测时发现内存暴涨或卡顿。









