📘 C++ <utility> 头文件详解
<utility> 是 C++ 中一个集合了多种通用小工具的头文件,包含:变量交换、移动语义工具、成对数据结构、小型辅助标签类型等。无论是写基础程序还是 STL、高级模板,都离不开 <utility>。
1. <utility> 的作用概览
<utility> 提供以下功能:
🔹 常用工具函数
std::swap:交换两个变量的值std::move:将对象转换为“右值引用”,触发移动语义std::forward:用于模板的“完美转发”std::exchange:设置新值并返回旧值std::as_const:创建 const 引用
🔹 常用小型类型
std::pair:存储两个相关值std::make_pair:自动推导类型并构造 pair- 一些用于容器内部构造的标签类型(例如
std::in_place_t)
🔹 模板元编程工具
std::integer_sequencestd::index_sequence
这些用于编译期生成序列,多用于模板库实现。
2. std::pair —— 成对存储两个值
std::pair<T1, T2> 是一个简单的模板结构体,用于把两个类型不同的值绑定在一起。
2.1 定义形式
template<class T1, class T2>
struct pair {
T1 first;
T2 second;
};
2.2 基本使用
pair<int, string> p(10, "hello");
cout << p.first; // 10
cout << p.second; // hello
2.3 通过 make_pair 创建
auto p = make_pair(3, 4.5); // 自动类型推导
2.4 常见用途
- map 的键值对:
map.insert(make_pair(key, value)); - 坐标 pair:
pair<int,int>(x, y) - 返回多个值
3. std::swap —— 通用交换函数
swap 是 <utility> 最常用的函数之一。
3.1 用法
int a = 3, b = 5;
swap(a, b); // a=5, b=3
3.2 底层原理
template<class T>
void swap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
3.3 特点
- 是模板,可以交换任意类型
- 对 STL 容器优化过:交换是 **O(1)**(交换内部指针而不是逐个元素)
例如:
vector<int> a, b;
swap(a, b); // 仅交换指针
用于矩阵原地转置:
swap(a[i][j], a[j][i]);
4. std::move —— 移动语义的核心工具
std::move 并不移动对象,而是将对象转换为右值引用,表示“可以被抢资源”。
4.1 示例
string a = "hello";
string b = std::move(a);
效果:
- b 获得 a 的数据
- a 被清空或处于“有效但未指定状态”
4.2 底层原理(简化)
template<class T>
T&& move(T& t) {
return static_cast<T&&>(t);
}
5. std::forward —— 完美转发
用于模板,让参数保持原本的左值/右值属性。
5.1 示例(理解即可)
template<class T, class... Args>
T factory(Args&&... args) {
return T(std::forward<Args>(args)...);
}
用途:
- 保留参数的引用类别
- 避免不必要的拷贝
属于进阶模板知识。
6. 多用途工具函数
6.1 std::exchange —— 设置新值并返回旧值
int x = 10;
int old = std::exchange(x, 42);
// old = 10
// x = 42
常用于状态机、swap+返回旧状态的场景。
6.2 std::as_const —— 把对象变成 const 引用
int x = 5;
auto& r = std::as_const(x); // r: const int&
// r = 7; // ❌ 错误
7. 高阶:模板元编程工具
7.1 std::integer_sequence
在编译期生成一串整数。
7.2 std::index_sequence
主要用于展开 tuple:
template<typename Tuple, size_t... I>
void print(const Tuple& t, index_sequence<I...>) {
((cout << get<I>(t) << " "), ...);
}
这些通常用于:
- tuple 展开
- 完美转发
- 编译期运算
8. 实用总结
下面是 <utility> 中最常用的部分:
| 名称 | 用途 | 初学者重要度 |
|---|---|---|
std::swap |
通用变量交换 | ⭐⭐⭐⭐⭐ |
std::pair |
成对存储两个值 | ⭐⭐⭐⭐ |
std::make_pair |
更简单创建 pair | ⭐⭐⭐⭐ |
std::move |
触发移动语义 | ⭐⭐⭐ |
std::forward |
完美转发(模板) | ⭐⭐ |
std::exchange |
设置新值并返回旧值 | ⭐⭐ |
std::as_const |
创建 const 引用 | ⭐ |
std::index_sequence |
高级模板 | ⭐ |
9. 示例:原地矩阵转置使用 <utility>
#include <iostream>
#include <utility>
using namespace std;
int main() {
int n;
cin >> n;
int a[10][10];
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
cin >> a[i][j];
// 原地转置
for (int i = 0; i < n; ++i)
for (int j = i + 1; j < n; ++j)
swap(a[i][j], a[j][i]); // 来自 <utility>
// 输出
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (j) cout << " ";
cout << a[i][j];
}
cout << "\n";
}
}