C++ STL容器的swap函数通过交换内部指针和元数据,在O(1)时间内高效完成容器内容交换,避免了O(N)的元素复制,显著提升性能;同时因其noexcept特性,为异常安全提供强保证,尤其在copy-and-swap惯用法中确保操作的原子性与安全性;在泛型编程中,应结合ADL使用using std::swap; swap(a, b);以自动调用最优实现。

C++ STL容器的
swap
在C++ STL中,
swap
std::vector
std::list
std::deque
std::map
std::set
swap
谈到性能,
swap
std::vector
swap
所以,无论你的
vector
swap
立即学习“C++免费学习笔记(深入)”;
举个例子,假设我们有两个大
vector
#include <vector>
#include <iostream>
#include <chrono>
#include <algorithm> // for std::swap
int main() {
std::vector<int> vec1(10000000, 1); // 1000万个元素
std::vector<int> vec2(10000000, 2);
// 使用容器成员swap
auto start_member_swap = std::chrono::high_resolution_clock::now();
vec1.swap(vec2);
auto end_member_swap = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> member_swap_ms = end_member_swap - start_member_swap;
std::cout << "Member swap time: " << member_swap_ms.count() << " ms\n";
// 假设我们要模拟一个“手动”复制交换,虽然实际代码中不会这么写,但为了对比性能
// 这是一个非常低效的交换方式,仅作概念对比
// std::vector<int> temp = vec1; // 复制 vec1 到 temp (O(N))
// vec1 = vec2; // 复制 vec2 到 vec1 (O(N))
// vec2 = temp; // 复制 temp 到 vec2 (O(N))
// 这里的注释代码如果真的运行,会耗时非常久,通常是几百毫秒甚至秒级,与swap的微秒级形成鲜明对比。
// 为了更直观地展示O(N)和O(1)的区别,我们可以对比一下创建和销毁一个大vector的时间
// 假设我们现在想“清空”一个vector并用另一个vector的内容填充它
std::vector<int> original_vec(5000000, 3);
std::vector<int> new_data_vec(5000000, 4);
auto start_copy_assign = std::chrono::high_resolution_clock::now();
original_vec = new_data_vec; // 复制赋值,O(N)
auto end_copy_assign = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> copy_assign_ms = end_copy_assign - start_copy_assign;
std::cout << "Copy assignment time: " << copy_assign_ms.count() << " ms\n";
// 而如果用swap来实现类似“清空并填充”的效果,配合move语义
std::vector<int> another_vec(5000000, 5);
std::vector<int> temp_empty; // 一个空容器
auto start_swap_clear = std::chrono::high_resolution_clock::now();
another_vec.swap(temp_empty); // 此时another_vec变空,temp_empty持有原数据
// 如果我们想用new_data_vec的内容填充another_vec,可以这样做:
// std::vector<int> new_content(std::move(new_data_vec)); // 假设new_data_vec是临时的
// another_vec.swap(new_content); // O(1)
auto end_swap_clear = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> swap_clear_ms = end_swap_clear - start_swap_clear;
std::cout << "Swap to clear time (approx): " << swap_clear_ms.count() << " ms\n"; // 实际这里只算了swap操作本身
return 0;
}你会发现,
vec1.swap(vec2)
O(N)
swap
swap
在C++中,异常安全是一个非常重要的概念,尤其是在资源管理方面。
swap
经典的“copy-and-swap”惯用法就是基于
swap
swap
swap
考虑一个简单的自定义类,它管理着一块动态分配的内存:
#include <algorithm> // For std::swap
#include <stdexcept>
#include <iostream>
#include <vector>
class MyBuffer {
private:
int* data;
size_t size;
public:
// 构造函数
MyBuffer(size_t s) : data(nullptr), size(s) {
if (s > 0) {
data = new int[s];
// 模拟可能抛出异常的操作,例如填充数据
for (size_t i = 0; i < s; ++i) {
if (i == s / 2 && s > 10) { // 模拟在中间某个点抛出异常
// throw std::runtime_error("Simulated error during data fill");
}
data[i] = static_cast<int>(i);
}
}
std::cout << "MyBuffer constructed with size " << size << "\n";
}
// 析构函数
~MyBuffer() {
delete[] data;
std::cout << "MyBuffer destructed with size " << size << "\n";
}
// 拷贝构造函数
MyBuffer(const MyBuffer& other) : data(nullptr), size(other.size) {
if (other.size > 0) {
data = new int[other.size];
std::copy(other.data, other.data + other.size, data);
}
std::cout << "MyBuffer copy constructed with size " << size << "\n";
}
// 移动构造函数 (C++11)
MyBuffer(MyBuffer&& other) noexcept : data(other.data), size(other.size) {
other.data = nullptr;
other.size = 0;
std::cout << "MyBuffer move constructed with size " << size << "\n";
}
// swap 函数,noexcept 是关键
void swap(MyBuffer& other) noexcept {
using std::swap; // 引入std::swap,以防万一
swap(data, other.data);
swap(size, other.size);
std::cout << "MyBuffer swap performed\n";
}
// 拷贝赋值运算符 - 使用 copy-and-swap idiom
MyBuffer& operator=(MyBuffer other) noexcept { // 注意这里是传值参数,会调用拷贝构造函数
swap(other); // 交换this和other的内容
std::cout << "MyBuffer copy assignment performed\n";
return *this;
}
size_t getSize() const { return size; }
};
int main() {
try {
MyBuffer b1(10); // 原始对象
std::cout << "b1 size: " << b1.getSize() << "\n";
// 尝试进行一个可能失败的赋值操作
// MyBuffer b2(5); // 临时对象,用于模拟赋值
// b2 = MyBuffer(20); // 赋值,这里会调用拷贝构造和copy-and-swap
// std::cout << "b2 size: " << b2.getSize() << "\n";
// 演示copy-and-swap的异常安全性
std::cout << "\nAttempting copy assignment with potential failure:\n";
MyBuffer b3(5);
std::cout << "b3 initial size: " << b3.getSize() << "\n";
try {
// 假设MyBuffer(1000)在构造时可能抛出异常
// MyBuffer temp(1000); // 如果这里抛异常,b3不受影响
// b3 = temp; // 如果拷贝构造成功,再进行swap
b3 = MyBuffer(1000); // 临时对象的构造如果在内部抛出异常,b3状态不变
} catch (const std::runtime_error& e) {
std::cerr << "Caught exception: " << e.what() << "\n";
}
std::cout << "b3 final size after potential failure: " << b3.getSize() << "\n"; // b3状态未变
} catch (const std::exception& e) {
std::cerr << "Main catch block: " << e.what() << "\n";
}
return 0;
}在这个例子中,
MyBuffer
operator=
MyBuffer
operator=
operator=
*this
operator=
swap(other)
noexcept
STL容器自身的
swap
noexcept
std::swap
swap
这其实是一个C++编程中比较细致但也非常重要的问题,尤其是在编写泛型代码时。
首先,
std::swap
<utility>
<algorithm>
template <class T>
void swap(T& a, T& b) {
T temp = std::move(a); // 或者 T temp(a);
a = std::move(b); // 或者 a = b;
b = std::move(temp); // 或者 b = temp;
}这个默认的
std::swap
然而,对于STL容器来说,它们都提供了自己的
swap
std::vector::swap
std::list::swap
noexcept
那么问题来了,我们什么时候用哪个?
当你直接操作一个特定类型的STL容器时,比如你有一个
std::vector<int> v1, v2;
v1.swap(v2);
std::vector
swap
但如果你在编写泛型代码,例如一个函数模板,它接受两个任意类型的参数,并希望交换它们,这时候就应该使用
std::swap
正确的泛型
swap
template <typename T>
void generic_swap_function(T& a, T& b) {
using std::swap; // 引入std::swap到当前作用域
swap(a, b); // 调用无限定的swap
}这里的
using std::swap;
std::swap
swap(a, b);
a
b
swap
a
b
std::vector
std::vector
swap
swap
std::swap
对于STL容器而言,
std::swap
std::swap(vec1, vec2)
vec1.swap(vec2)
using std::swap; swap(a, b);
swap
swap
swap
std::swap
所以,结论是:
container.swap(other_container);
using std::swap; swap(a, b);
swap
swap
swap
swap
一个典型的应用场景是std::vector::shrink_to_fit()
vector
std::vector
shrink_to_fit()
swap
std::vector<int> myVec = {1, 2, 3, 4, 5};
myVec.reserve(100); // 容量现在是100
// ... 之后移除了很多元素,只剩下5个
// 想要收缩容量
std::vector<int>(myVec).swap(myVec);这里发生了什么?
std::vector<int>(myVec)
vector
myVec
myVec
vector
myVec.size()
swap
vector
myVec
myVec
vector
再比如,在一些排序算法中,
swap
partition
swap
std::move
swap
swap
最后,在实现一些自定义数据结构时,
swap
swap
swap
以上就是C++STL容器swap函数使用场景的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号