目录
std::not_equal_to<>: 用于比较两个值是否不相等。
std::greater<>: 用于比较两个值,判断第一个值是否大于第二个值。
std::less<>: 用于比较两个值,判断第一个值是否小于第二个值。
std::wiostream, std::wistream, std::wostream:
std::chrono::high_resolution_clock:
使用 std::tie 存储多个变量到 std::tuple
使用 std::apply 应用函数到 std::tuple 元素
std::is_member_function_pointer
std::filesystem::directory_entry
std::filesystem::filesystem_error
C++ 标准库(STL)提供了大量基于模板的组件,这些组件极大地增加了语言的表达能力和实用性。以下是一些 C++ 标准库中模板类型的实例:
C++ 标准库(STL)非常庞大,包含了众多的模板类型。以下是一些主要类别的实例,以及它们各自的一些常见组件或特例:
1、容器(Containers):
1. std::vector
动态数组,支持随机访问。它的大小可以动态变化,提供快速的随机访问时间和 O(1)
时间复杂度的元素添加和删除操作。
std::vector<int> vec = {1, 2, 3}; // 初始化一个 vector
vec.push_back(4); // 添加一个元素
2. std::deque
双端队列,提供在两端的快速插入和删除操作。它适用于需要快速从两端添加或删除元素的场景。
std::deque<int> dq;
dq.push_back(10); // 在队列尾部添加一个元素
dq.push_front(20); // 在队列头部添加一个元素
3. std::array
固定大小的数组,其大小在编译时确定。它提供了数组的所有功能,但不包含任何指针,因此更安全。
std::array<int, 4> arr = {{1, 2, 3, 4}}; // 初始化一个固定大小的数组
4. std::list
双向链表,支持在任意位置的快速插入和删除操作。它适用于需要频繁插入和删除元素的场景。
std::list<int> lst;
lst.push_back(5); // 在链表尾部添加一个元素
lst.push_front(6); // 在链表头部添加一个元素
5. std::forward_list
单向链表,支持在头部或通过迭代器在其他位置快速插入或删除元素。它比 std::list
更节省内存,但在某些操作上效率较低。
std::forward_list<int> fl;
fl.push_front(7); // 在链表头部添加一个元素
6. std::set
有序集合,元素唯一,通常基于平衡树实现。它保证元素处于排序状态,提供对唯一元素的快速查找和删除。
std::set<int> s;
s.insert(1); // 添加一个元素
7. std::map
有序的键值对集合,键唯一,通常基于平衡树实现。它允许你通过键来快速查找和访问值。
std::map<std::string, int> m;
m["apple"] = 1; // 添加一个键值对
8. std::multiset
允许键值重复的 std::set
。它存储了多个相同的元素。
std::multiset<int> ms;
ms.insert(1); // 添加一个元素
ms.insert(1); // 可以再次添加相同的元素
9. std::multimap
允许键值重复的 std::map
。它存储了多个具有相同键的元素。
std::multimap<std::string, int> mm;
mm.insert({"apple", 1}); // 添加一个键值对
mm.insert({"banana", 2}); // 添加另一个键值对
10. std::unordered_set
无序的唯一元素集合,基于哈希表实现。它提供平均恒定时间的查找和删除操作,但元素不保证有序。
std::unordered_set<int> us;
us.insert(3); // 添加一个元素
11. std::unordered_map
无序的键值对集合,基于哈希表实现。它允许快速访问和存储键值对,但键必须唯一。
std::unordered_map<std::string, int> um;
um["orange"] = 2; // 添加一个键值对
12. std::unordered_multiset
允许键值重复的 std::unordered_set
。
std::unordered_multiset<int> ums;
ums.insert(3); // 添加一个元素
ums.insert(3); // 可以再次添加相同的元素
13. std::unordered_multimap
允许键值重复的 std::unordered_map
。
std::unordered_multimap<std::string, int> umm;
umm.insert({"apple", 1}); // 添加一个键值对
umm.insert({"apple", 2}); // 可以添加具有相同键的另一个键值对
2、迭代器(Iterators)
这些是 C++ 标准库中定义的迭代器适配器,它们提供了一种方式来改变现有迭代器的行为,以适应不同的编程需求。
输入迭代器(std::istream_iterator
)
std::istream_iterator
用作输入流的迭代器,它可以从输入流(如 std::cin
)中读取元素,直到遇到输入结束符。
#include <iostream>
#include <iterator>
#include <vector>
int main() {
std::istream_iterator<int> int_in(std::cin), int_eof;
std::vector<int> v;
while (int_in != int_eof) {
v.push_back(*int_in++);
}
return 0;
}
在这个例子中,程序将读取整数值直到遇到输入结束符(如 EOF 或 Ctrl+D/Ctrl+Z),并将这些值存储在 std::vector
中。
输出迭代器(std::ostream_iterator
)
std::ostream_iterator
用作输出流的迭代器,它可以将元素写入输出流(如 std::cout
)。
#include <iostream>
#include <iterator>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
std::ostream_iterator<int> int_out(std::cout, " ");
std::copy(v.begin(), v.end(), int_out);
return 0;
}
此代码段将向标准输出流复制并打印 std::vector
中的整数值,元素之间以空格分隔。
反向迭代器(reverse_iterator
)
reverse_iterator
是一个迭代器适配器,它允许以相反的方向遍历序列(从后向前)。
#include <iostream>
#include <iterator>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
for (std::vector<int>::reverse_iterator it = v.rbegin(); it != v.rend(); ++it) {
std::cout << *it << " ";
}
return 0;
}
这个例子将反向遍历 std::vector
并打印其元素。
std::move_iterator
std::move_iterator
是一个迭代器适配器,它将迭代器所指向的每个元素转换为右值引用,这有助于实现移动语义,从而在某些情况下提高性能。
#include <iostream>
#include <iterator>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
std::vector<int> v2;
v2.reserve(v.size());
std::move_iterator<std::vector<int>::iterator> mit(v.begin());
std::move_iterator<std::vector<int>::iterator> mit_end(v.end());
std::move_backward(mit, mit_end - 1, v2.end());
return 0;
}
在这个例子中,std::move_backward
算法与 std::move_iterator
结合使用,以在移动而非复制元素的情况下,从 v
向后移动元素到 v2
。
3、算法(Algorithms)
C++ 标准库中的算法可以根据它们的行为和用途被分为几个不同的类别。以下是每个类别的介绍和相应的示例:
非修改性序列算法
这些算法不会改变它们的输入序列。
-
std::all_of
: 检查是否序列中的所有元素都满足某个条件。bool allPositive = std::all_of(v.begin(), v.end(), [](int i) { return i > 0; });
-
std::any_of
: 检查序列中是否存在至少一个元素满足某个条件。bool hasPositive = std::any_of(v.begin(), v.end(), [](int i) { return i > 0; });
-
std::none_of
: 检查序列中是否没有元素满足某个条件。bool allNegative = std::none_of(v.begin(), v.end(), [](int i) { return i >= 0; });
修改性序列算法
这些算法会改变它们的输入序列。
-
std::fill
: 用一个特定值填充一个序列。std::fill(v.begin(), v.end(), 0); // 将 v 中的所有元素设置为 0
-
std::replace
: 替换序列中满足条件的元素。std::replace(v.begin(), v.end(), 0, 1); // 将 v 中所有值为 0 的元素替换为 1
-
std::remove
: 移除序列中满足条件的元素,返回新序列的末尾迭代器。v.erase(std::remove(v.begin(), v.end(), 0), v.end()); // 移除 v 中所有值为 0 的元素
排序算法
-
std::sort
: 对序列进行排序。std::sort(v.begin(), v.end()); // 排序 v 中的元素
-
std::stable_sort
: 对序列进行稳定的排序,即相等元素的顺序不变。std::stable_sort(v.begin(), v.end()); // 稳定排序 v 中的元素
二分算法
这些算法用于在已排序的序列中进行查找操作。
-
std::lower_bound
: 查找序列中小于或等于某个值的第一个元素的迭代器。auto it = std::lower_bound(v.begin(), v.end(), 3); // 查找 v 中第一个不小于 3 的元素
-
std::upper_bound
: 查找序列中大于某个值的第一个元素的迭代器。auto it = std::upper_bound(v.begin(), v.end(), 3); // 查找 v 中第一个大于 3 的元素
集合算法
这些算法用于执行集合操作,如并集、交集。
-
std::includes
: 检查一个序列是否包含另一个序列的所有元素。std::vector<int> v1 = {1, 2, 3}; std::vector<int> v2 = {2, 3}; bool includes = std::includes(v1.begin(), v1.end(), v2.begin(), v2.end());
-
std::set_union
: 将两个序列的并集存储在第三个序列中。std::vector<int> vUnion(v1.size() + v2.size()); std::set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), vUnion.begin());
-
std::set_intersection
: 将两个序列的交集存储在第三个序列中。std::vector<int> vIntersection; std::set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(vIntersection));
堆算法
-
std::push_heap
: 将一个元素添加到堆中,维护堆的属性。std::push_heap(v.begin(), v.end(), std::greater<int>()); // 将 v 作为最大堆处理
-
std::pop_heap
: 移除堆顶元素(最大元素),维护堆的属性,并返回新堆的末尾迭代器。std::pop_heap(v.begin(), v.end(), std::greater<int>()); // 移除 v 中的最大元素 v.pop_back(); // 从容器中实际移除元素
随机算法
std::random_shuffle
: 随机地重新排列序列中的元素。std::random_shuffle(v.begin(), v.end()); // 随机打乱 v 中的元素
4、函数对象(Functional)
在C++标准库中,<functional>
头文件提供了一组函数对象,它们是作为模板参数传递的函数的特化形式。这些函数对象可以像函数一样使用,但它们是对象,因此可以拥有状态(例如,成员变量)和/或行为(例如,成员函数)。这些函数对象常用于标准库算法中,以提供自定义的比较或运算逻辑。
-
std::plus<>
: 用于执行加法运算。#include <functional> #include <algorithm> #include <vector> #include <iostream> std::vector<int> v = {1, 2, 3, 4, 5}; int sum = std::accumulate(v.begin(), v.end(), 0, std::plus<>()); std::cout << "Sum: " << sum << std::endl; // 输出 15
-
std::minus<>
: 用于执行减法运算。int difference = std::inner_product(v.begin(), v.end(), v.begin(), 0, std::plus<>(), std::minus<>()); std::cout << "Difference: " << difference << std::endl; // 输出 0,因为每个元素减去它自己都是0
-
std::multiplies<>
: 用于执行乘法运算。std::vector<int> v2 = {2, 3, 4}; int product = std::accumulate(v.begin(), v.end(), 1, std::multiplies<>()); std::cout << "Product: " << product << std::endl; // 输出 120
-
std::divides<>
: 用于执行除法运算。std::vector<double> v3 = {10, 5, 2}; double quotient = std::accumulate(v3.begin(), v3.end(), 10.0, std::divides<>()); std::cout << "Quotient: " << quotient << std::endl; // 输出 0.1
-
std::negate<>
: 用于对数值取反。std::vector<int> v4 = {1, 2, 3}; std::transform(v4.begin(), v4.end(), v4.begin(), std::negate<>()); for (int i : v4) { std::cout << i << " "; // 输出 -1 -2 -3 }
-
std::equal_to<>
: 用于比较两个值是否相等。std::vector<int> v5 = {1, 2, 3, 4, 5}; auto it = std::find_if(v.begin(), v.end(), std::bind2nd(std::equal_to<>(), 3)); if (it != v.end()) { std::cout << "Found: " << *it << std::endl; // 输出 3 }
-
std::not_equal_to<>
: 用于比较两个值是否不相等。auto it2 = std::find_if(v.begin(), v.end(), std::not_equal_to<>()); // 这个例子可能需要更多的上下文来展示,因为not_equal_to需要两个参数
-
std::greater<>
: 用于比较两个值,判断第一个值是否大于第二个值。std::sort(v.begin(), v.end(), std::greater<>()); for (int i : v) { std::cout << i << " "; // 输出 5 4 3 2 1 }
-
std::less<>
: 用于比较两个值,判断第一个值是否小于第二个值。std::sort(v.begin(), v.end(), std::less<>()); for (int i : v) { std::cout << i << " "; // 输出 1 2 3 4 5 }
-
std::logical_and<>
: 用于逻辑与操作。auto it3 = std::find_if(v.begin(), v.end(), std::bind2nd(std::logical_and<bool>(), std::bind2nd(std::greater<>(), 3))); if (it3 != v.end()) { std::cout << "Found greater than 3: " << *it3 << std::endl; // 输出 4 和 5 }
-
std::logical_or<>
: 用于逻辑或操作。// 类似于logical_and,需要更多的上下文来展示
-
std::bit_and<>
: 用于按位与操作。std::vector<int> v6 = {6, 5, 3}; std::transform(v6.begin(), v6.end(), v6.begin(), v6.begin(), std::bit_and<>()); for (int i : v6) { std::cout << i << " "; // 输出 2 5 3 }
5、输入/输出(I/O):
C++中的I/O流类是处理输入输出的基础,它们允许程序以一种统一的方式与各种输入输出设备进行交互。以下是对您提到的各个流类的简要介绍和示例:
std::iostream
:
std::iostream
是C++标准库中的一个类,它是std::istream
和std::ostream
的公共基类,允许进行输入和输出操作。std::cin
和std::cout
是std::iostream
的两个实例,分别用于标准输入和标准输出。
#include <iostream>
int main() {
std::cout << "Hello, World!" << std::endl; // 输出到控制台
return 0;
}
std::istream
:
std::istream
是用于输入操作的基类,提供了从输入流中读取数据的方法。
#include <iostream>
#include <string>
int main() {
std::string str;
std::cout << "Enter your name: ";
std::getline(std::cin, str); // 从标准输入读取一行
std::cout << "Hello, " << str << "!" << std::endl;
return 0;
}
std::ostream
:
std::ostream
是用于输出操作的基类,提供了向输出流中写入数据的方法。
#include <iostream>
int main() {
int number = 10;
std::cout << "The number is: " << number << std::endl; // 输出到控制台
return 0;
}
std::stringstream
:
std::stringstream
是一个类模板,允许使用流式操作来处理字符串。它可以用来构建和解析字符串,就像它们是流一样。
#include <iostream>
#include <sstream>
int main() {
std::stringstream ss;
ss << "The answer is " << 42; // 向字符串流写入数据
std::string data;
ss >> data; // 从字符串流读取数据
std::cout << data << std::endl; // 输出: The answer is
return 0;
}
std::wiostream
, std::wistream
, std::wostream
:
这些类是宽字符版本的输入输出流类,用于处理宽字符(如Unicode字符)。它们允许程序以统一的方式处理国际化的文本。
#include <wiostream>
int main() {
std::wcout << L"Hello, World!" << std::endl; // 使用宽字符输出流
return 0;
}
请注意,宽字符流的使用在实际编程中不如单字节流常见,因为它们主要用于处理需要国际化支持的程序。在大多数英文环境下,使用std::iostream
、std::istream
和std::ostream
已经足够。
6、字符串和文本处理:
在C++中,std::string
、std::wstring
、std::u16string
和std::u32string
都是定义在<string>
头文件中的类模板,它们提供了对字符串的存储和操作。这些类模板分别用于处理不同类型的字符:
std::string
:
用于处理普通的单字节字符(通常是ASCII或基于单字节编码的字符集,如ISO-8859-1或扩展ASCII)。
#include <iostream>
#include <string>
int main() {
std::string str = "Hello, World!";
std::cout << str << std::endl; // 输出: Hello, World!
return 0;
}
std::wstring
:
用于处理宽字符字符串(wchar_t
类型),通常用于存储Unicode字符,但具体取决于编译器和平台。在一些平台上,wchar_t
可能是2字节(如UTF-16),而在其他平台上可能是4字节(如UTF-32)。
#include <iostream>
#include <string>
int main() {
std::wstring wstr = L"Hello, World!";
std::wcout << wstr << std::endl; // 使用宽字符输出流
return 0;
}
std::u16string
:
用于处理UTF-16编码的16位Unicode字符。
#include <iostream>
#include <string>
int main() {
std::u16string u16str = u"Hello, World!";
for (char16_t ch : u16str) {
std::cout << std::hex << static_cast<int>(ch) << " "; // 以十六进制形式输出每个字符代码
}
std::cout << std::endl;
return 0;
}
std::u32string
:
用于处理UTF-32编码的32位Unicode字符。
#include <iostream>
#include <string>
int main() {
std::u32string u32str = U"Hello, World!";
for (char32_t ch : u32str) {
std::cout << std::hex << static_cast<unsigned int>(ch) << " "; // 以十六进制形式输出每个字符代码
}
std::cout << std::endl;
return 0;
}
7、数值操作:
std::valarray
对于数值计算和科学计算中的批量数据处理非常有用,尤其是当你需要对数组进行复杂的数学运算时。然而,对于非数值类型的容器操作,std::vector
通常是更灵活和常用的选择。
std::valarray
-
以下是
std::valarray
的一些基本用法和示例: -
创建和初始化:
#include <valarray> int main() { std::valarray<double> va(5); // 创建一个包含5个double元素的valarray,初始值未定义 std::valarray<double> vb(3.14, 5); // 创建一个包含5个元素的valarray,每个元素都初始化为3.14 return 0; }
-
数组操作:
使用std::valarray
可以对数组中的所有元素应用数学操作。#include <iostream> #include <valarray> int main() { std::valarray<double> va(5); for (size_t i = 0; i < va.size(); ++i) { va[i] = i + 1; // 初始化数组 } std::valarray<double> vb = va * 2; // 将数组中的每个元素乘以2 std::cout << "Original array: "; for (double elem : va) { std::cout << elem << ' '; } std::cout << std::endl; std::cout << "Multiplied by 2: "; for (double elem : vb) { std::cout << elem << ' '; } std::cout << std::endl; return 0; }
-
使用数学函数:
std::valarray
提供了对数组应用标准数学函数的能力。#include <iostream> #include <valarray> #include <cmath> int main() { std::valarray<double> va = {1, 2, 3, 4, 5}; std::valarray<double> squares = std::sqrt(va); // 计算每个元素的平方根 std::cout << "Squares of original array: "; for (double elem : squares) { std::cout << elem << ' '; } std::cout << std::endl; return 0; }
-
切片和索引:
std::valarray
允许通过切片和索引进行更复杂的操作。#include <iostream> #include <valarray> int main() { std::valarray<double> va = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // 使用切片数组访问数组的子集 std::valarray<double> evens = va[std::slice(0, 5, 2)]; // 从第1个元素开始,步长为2,取5个元素 std::cout << "Even indexed elements: "; for (double elem : evens) { std::cout << elem << ' '; } std::cout << std::endl; return 0; }
-
数学运算符重载:
std::valarray
重载了多种数学运算符,使得可以方便地进行数组间的运算。#include <iostream> #include <valarray> int main() { std::valarray<double> va = {1, 2, 3, 4, 5}; std::valarray<double> vb = {5, 4, 3, 2, 1}; std::valarray<double> vc = va + vb; // 两个数组对应元素相加 std::cout << "Sum of corresponding elements: "; for (double elem : vc) { std::cout << elem << ' '; } std::cout << std::endl; return 0; }
8、动态内存管理:
std::unique_ptr
:
std::unique_ptr
是一种拥有并管理一个对象的独占所有权的智能指针。它确保指针指向的资源在std::unique_ptr
被销毁时也会被释放。
#include <memory>
#include <iostream>
class MyObject {
public:
MyObject() { std::cout << "MyObject created." << std::endl; }
~MyObject() { std::cout << "MyObject destroyed." << std::endl; }
};
int main() {
std::unique_ptr<MyObject> obj(new MyObject()); // 创建并自动管理对象
return 0; // obj离开作用域时自动销毁MyObject
}
std::shared_ptr
:
std::shared_ptr
是一种智能指针,它通过引用计数来管理对象的生命周期。多个std::shared_ptr
可以共享同一资源,当最后一个引用被销毁或解除绑定时,对象会被删除。
#include <memory>
#include <iostream>
class MyObject;
int main() {
std::shared_ptr<MyObject> obj1(new MyObject());
std::shared_ptr<MyObject> obj2 = obj1; // obj1和obj2共享同一对象
// 当obj1和obj2都离开作用域时,引用计数为0,MyObject被销毁
return 0;
}
std::weak_ptr
:
std::weak_ptr
是一种不控制对象生命周期的智能指针,它持有对管理对象的弱引用。std::weak_ptr
通常与std::shared_ptr
配合使用,解决std::shared_ptr
可能导致的循环引用问题。
#include <memory>
#include <iostream>
int main() {
std::shared_ptr<int> sp(new int(42));
std::weak_ptr<int> wp(sp); // wp是sp的弱引用
// sp离开作用域后,wp仍然可以检查其是否还引用着一个对象
if (wp.lock() != nullptr) {
std::cout << "Weak pointer still references an object." << std::endl;
}
return 0;
}
9、异常:
std::exception
:
std::exception
是C++标准库中所有异常的基类。它提供了错误信息的获取方法。
#include <exception>
try {
// 可能抛出异常的代码
} catch (const std::exception& e) {
std::cout << "Caught exception: " << e.what() << std::endl;
}
std::runtime_error
:
std::runtime_error
是std::exception
的派生类,用于报告运行时错误。
#include <stdexcept>
#include <iostream>
void riskyFunction() {
throw std::runtime_error("A runtime error occurred!");
}
int main() {
try {
riskyFunction();
} catch (const std::runtime_error& e) {
std::cout << "Caught runtime error: " << e.what() << std::endl;
}
}
std::invalid_argument
:
std::invalid_argument
是std::exception
的派生类,用于报告无效参数错误。
#include <stdexcept>
#include <iostream>
void validateArgument(bool arg) {
if (!arg) {
throw std::invalid_argument("Invalid argument provided!");
}
}
int main() {
try {
validateArgument(false);
} catch (const std::invalid_argument& e) {
std::cout << "Caught invalid argument: " << e.what() << std::endl;
}
}
10、线程支持:
std::thread
:
std::thread
用于创建和管理线程。你可以将一个函数或可调用对象传递给std::thread
的构造函数来在一个新线程中运行它。
#include <iostream>
#include <thread>
void printID() {
std::cout << "ID: " << std::this_thread::get_id() << '\n';
}
int main() {
std::thread t1(printID);
std::thread t2(printID);
t1.join();
t2.join(); // 等待线程t1和t2完成
return 0;
}
std::mutex
:
std::mutex
(互斥锁)用于保护共享数据不被多个线程同时访问,从而避免竞态条件。
#include <iostream>
#include <mutex>
#include <thread>
std::mutex mu;
int counter = 0;
void increment() {
for (int i = 0; i < 100; ++i) {
std::lock_guard<std::mutex> lock(mu); // 创建时锁定,析构时解锁
++counter;
}
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Counter: " << counter << std::endl; // 输出: Counter: 200
return 0;
}
std::recursive_mutex
:
std::recursive_mutex
是一种特殊类型的互斥锁,允许同一个线程多次锁定它。
#include <iostream>
#include <mutex>
#include <thread>
std::recursive_mutex mu;
void recursiveFunction(int n) {
if (n > 0) {
std::lock_guard<std::recursive_mutex> lock(mu);
recursiveFunction(n - 1);
}
std::cout << "n = " << n << std::endl;
}
int main() {
std::thread t1(recursiveFunction, 5);
t1.join();
return 0;
}
std::lock_guard
:
std::lock_guard
是一个作用域锁定器,它在构造时锁定互斥体,并在其作用域结束时自动解锁。
// 上面`std::mutex`的示例中已经展示了`std::lock_guard`的用法
std::unique_lock
:
std::unique_lock
比std::lock_guard
更灵活,它允许你锁定和解锁互斥体,并且可以转移所有权。
#include <iostream>
#include <mutex>
#include <thread>
std::mutex mu;
std::unique_lock<std::mutex> lock(mu); // 锁定互斥体
void doSomething() {
// 可以在此处执行需要互斥体保护的操作
lock.unlock(); // 显式解锁
// ...
lock.lock(); // 显式重新锁定
}
int main() {
std::thread t(doSomething);
t.join();
return 0;
}
11、原子操作:
std::atomic
:
std::atomic
是一个模板类,提供了一种操作原子类型的方式,确保了即使在并发环境中,对这些类型的操作也是“不可分割”的。
#include <atomic>
#include <thread>
std::atomic<int> atomicCounter(0); // 使用std::atomic封装原子型变量
void increment() {
for (int i = 0; i < 100; ++i) {
atomicCounter++; // 自增操作是原子的
}
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Atomic Counter: " << atomicCounter << std::endl; // 输出: Atomic Counter: 200
return 0;
}
std::atomic_bool
:
std::atomic_bool
是布尔类型(bool
)的原子版本。它提供了原子操作,如原子地读取、写入和修改布尔值。
#include <atomic>
#include <thread>
int main() {
std::atomic_bool flag(true);
std::thread t([&flag]() {
// 原子地改变flag的值
flag.store(false);
});
t.join(); // 等待线程完成
// 原子地读取flag的值
if (flag.load()) {
std::cout << "Flag is true." << std::endl;
} else {
std::cout << "Flag is false." << std::endl;
}
return 0;
}
std::atomic_char
:
std::atomic_char
是字符类型(char
)的原子版本。它允许对字符变量进行原子操作。
#include <atomic>
#include <thread>
int main() {
std::atomic_char value('A');
std::thread t([&value]() {
// 原子地修改字符
value.store('B');
});
t.join();
std::cout << "Value: " << value.load() << std::endl; // 输出: Value: B
return 0;
}
std::atomic_schar
:
std::atomic_schar
是有符号字符类型(signed char
)的原子版本。
#include <atomic>
#include <thread>
int main() {
std::atomic_schar value(10);
std::thread t([&value]() {
// 原子地增加值
value += 5;
});
t.join();
std::cout << "Value: " << static_cast<int>(value.load()) << std::endl; // 输出: Value: 15
return 0;
}
std::atomic_uchar
:
std::atomic_uchar
是无符号字符类型(unsigned char
)的原子版本。
#include <atomic>
#include <thread>
int main() {
std::atomic_uchar value(100);
std::thread t([&value]() {
// 原子地减少值
value -= 20;
});
t.join();
std::cout << "Value: " << static_cast<int>(value.load()) << std::endl; // 输出: Value: 80
return 0;
}
这些原子类型提供了一种在多线程环境中安全地操作基本数据类型的方式,无需手动使用互斥锁。它们确保了操作的原子性,从而避免了竞态条件和内存模型的复杂性。
请注意,虽然原子操作通常比使用互斥锁更高效,但在某些情况下,如果操作较为复杂或需要同步多个变量,使用互斥锁可能仍然是必要的。此外,原子操作并不能完全替代互斥锁,因为它们不提供互斥锁的高级功能,如条件变量和锁的层次结构。
12、时间日期:
std::chrono::system_clock
:
std::chrono::system_clock
是一个时钟,它表示系统时间,即通常意义上的时间,包括日期和时间。它可能受到系统时间变化(如夏令时变化或手动调整)的影响。
#include <iostream>
#include <chrono>
int main() {
using namespace std::chrono;
auto now = system_clock::now();
system_clock::time_point after_10_seconds = now + seconds(10);
std::cout << "Current time: " << system_clock::to_time_t(now) << '\n'
<< "Time after 10 seconds: " << system_clock::to_time_t(after_10_seconds) << '\n';
return 0;
}
std::chrono::steady_clock
:
std::chrono::steady_clock
是一个始终向前推进的时钟,它保证了单调性,即不会受到系统时间变化的影响,也不会倒退。它通常用于性能测量。
#include <iostream>
#include <chrono>
int main() {
auto start = std::chrono::steady_clock::now();
// 模拟一些操作
std::this_thread::sleep_for(std::chrono::milliseconds(500));
auto end = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
std::cout << "Time taken: " << duration << " milliseconds" << std::endl;
return 0;
}
std::chrono::high_resolution_clock
:
std::chrono::high_resolution_clock
是 std::chrono
中最高精度的时钟,通常与 std::chrono::steady_clock
是同一种时钟,除非平台提供了更高的精度时钟。
// 使用方式与 std::chrono::steady_clock 相同
std::chrono::duration
:
std::chrono::duration
是一个模板类,用于表示时间间隔。它需要两个模板参数:第一个是用于表示持续时间的类型(通常是 int
、long long
或 double
),第二个是时间单位的分数(如 std::ratio
)。
#include <iostream>
#include <chrono>
int main() {
using namespace std::chrono;
auto duration = seconds(5); // 创建一个持续5秒的duration
std::cout << "Duration in milliseconds: "
<< duration_cast<milliseconds>(duration).count() << " ms\n";
return 0;
}
std::chrono::time_point
:
std::chrono::time_point
是一个模板类,表示特定时钟的某个时间点。它通常与 std::chrono::duration
一起使用,以表示从时间线起点开始的时间长度。
#include <iostream>
#include <chrono>
int main() {
using namespace std::chrono;
time_point<system_clock> t1 = system_clock::now();
std::cout << "Current date and time: " << system_clock::to_time_t(t1) << '\n';
return 0;
}
std::chrono
库提供了一套完整的工具来处理时间点和持续时间,非常适合用于时间测量、性能分析和截止日期的计算。它通过提供高精度和低延迟的操作,帮助开发者在时间相关的编程任务中获得更好的控制和精度。
13、智能指针:
std::unique_ptr
std::unique_ptr
是一种拥有式智能指针,它拥有其指向的对象,并确保同一时间只有一个 std::unique_ptr
实例拥有该对象。当 std::unique_ptr
被销毁时,它会自动删除其所指向的对象。
#include <memory>
#include <iostream>
class Resource {
public:
Resource() { std::cout << "Resource created." << std::endl; }
~Resource() { std::cout << "Resource destroyed." << std::endl; }
};
int main() {
std::unique_ptr<Resource> resource(new Resource()); // 创建并自动管理Resource对象
return 0; // resource离开作用域时自动销毁Resource对象
}
std::shared_ptr
std::shared_ptr
是一种引用计数的智能指针,它允许多个 std::shared_ptr
实例共享同一对象。对象会在最后一个引用它的 std::shared_ptr
被销毁或被赋值为空时自动删除。
#include <memory>
#include <iostream>
int main() {
std::shared_ptr<Resource> resource1(new Resource());
std::shared_ptr<Resource> resource2 = resource1; // resource1和resource2共享Resource对象
// 当resource1和resource2都离开作用域时,引用计数归零,Resource对象被销毁
return 0;
}
std::weak_ptr
std::weak_ptr
是一种不控制对象生命周期的智能指针,它持有对管理对象的弱引用。std::weak_ptr
通常与 std::shared_ptr
配合使用,解决 std::shared_ptr
可能导致的循环引用问题。
#include <memory>
#include <iostream>
int main() {
std::shared_ptr<Resource> resource(new Resource());
std::weak_ptr<Resource> weakResource = resource; // weakResource是resource的弱引用
// 即使resource离开作用域,weakResource仍然有效,直到其重新绑定到另一个shared_ptr
resource.reset(); // 显式地删除shared_ptr所管理的对象
if (auto sharedResource = weakResource.lock()) { // 尝试获取强引用
std::cout << "Weak pointer still references an object." << std::endl;
} else {
std::cout << "Weak pointer no longer references an object." << std::endl;
}
return 0;
}
智能指针的使用减少了手动管理内存的复杂性,并且通过自动释放动态分配的对象,减少了内存泄漏的风险。它们是现代C++编程中处理动态内存的标准方式。
14、正则表达式:
std::regex
std::regex
是一个类模板,表示一个编译后的正则表达式。它可以用来与字符串进行匹配。
#include <iostream>
#include <string>
#include <regex>
int main() {
std::regex pattern("hello\s+\\S+"); // 匹配"hello"后面跟着一个或多个空白字符,然后是一个或多个非空白字符
std::string text = "hello world!";
if (std::regex_search(text, pattern)) {
std::cout << "Match found." << std::endl;
} else {
std::cout << "No match found." << std::endl;
}
return 0;
}
std::match_results
std::match_results
是一个类模板,用于存储正则表达式匹配的结果。它包含了匹配的子串、位置和长度等信息。
#include <iostream>
#include <string>
#include <regex>
int main() {
std::regex pattern("(\\d{4})-(\\d{2})-(\\d{2})");
std::string text = "Today's date is 2023-04-05.";
std::match_results<std::string::const_iterator> matches;
if (std::regex_search(text, matches, pattern)) {
std::cout << "Year: " << matches[1] << "\n";
std::cout << "Month: " << matches[2] << "\n";
std::cout << "Day: " << matches[3] << "\n";
}
return 0;
}
std::regex_iterator
std::regex_iterator
是一个迭代器适配器,它使用正则表达式引擎在给定范围内迭代地搜索匹配项。
#include <iostream>
#include <string>
#include <regex>
int main() {
std::regex pattern("\\d+"); // 匹配一个或多个数字
std::string text = "There are 123 apples and 456 oranges";
std::regex_iterator<std::string::const_iterator> it(text.begin(), text.end(), pattern);
std::regex_iterator<std::string::const_iterator> end;
while (it != end) {
std::cout << "Found number: " << *it << std::endl;
++it;
}
return 0;
}
std::regex_token_iterator
std::regex_token_iterator
是一个迭代器适配器,它使用正则表达式引擎在给定范围内迭代地提取匹配的子表达式或分组。
#include <iostream>
#include <string>
#include <regex>
int main() {
std::regex pattern("(\\w+)\\s*=\\s*(\\w+)"); // 匹配形如"var = value"的模式
std::string text = "width=100 height=200";
std::regex_token_iterator<std::string::const_iterator> it(text.begin(), text.end(), pattern, -1);
std::regex_token_iterator<std::string::const_iterator> end;
while (it != end) {
std::cout << "Token: " << *it << std::endl;
++it;
}
return 0;
}
C++正则表达式库提供了强大的文本处理能力,可以用于各种文本搜索、替换和解析任务。使用这些工具,你可以编写出灵活且功能强大的文本处理程序。
15、元组(Tuples):
std::tuple
std::tuple
是 C++ 标准库中的一个类模板,它提供了一种将多个不同类型对象打包成一个单一对象的方式。std::tuple
可以存储不同类型的值,并且可以像数组或容器一样进行索引。
以下是 std::tuple
的一些基本用法和示例:
创建和初始化 std::tuple
#include <tuple>
#include <string>
#include <iostream>
int main() {
// 使用直接初始化
std::tuple<int, double, std::string> myTuple{1, 2.5, "example"};
// 使用 std::make_tuple 工厂函数
auto myTuple2 = std::make_tuple(2, 3.5, "another example");
return 0;
}
访问 std::tuple
元素
#include <tuple>
#include <iostream>
int main() {
std::tuple<int, double, std::string> myTuple{10, 20.5, "tuple value"};
// 使用 std::get 访问 tuple 元素
int i = std::get<0>(myTuple); // 获取第一个元素
double d = std::get<1>(myTuple); // 获取第二个元素
std::string s = std::get<2>(myTuple); // 获取第三个元素
std::cout << "Tuple contains: " << i << ", " << d << ", " << s << std::endl;
return 0;
}
使用 std::tie
存储多个变量到 std::tuple
#include <tuple>
#include <iostream>
int main() {
int a, b, c;
std::tie(a, b, c) = std::make_tuple(1, 2, 3);
std::cout << "a = " << a << ", b = " << b << ", c = " << c << std::endl;
return 0;
}
使用 std::apply
应用函数到 std::tuple
元素
#include <tuple>
#include <iostream>
int add(int a, int b) {
return a + b;
}
int main() {
std::tuple<int, int> myTuple{3, 4};
// 使用 std::apply 调用函数
int result = std::apply(add, myTuple);
std::cout << "The sum of the tuple elements is: " << result << std::endl;
return 0;
}
使用 std::get
访问特定类型的元素
#include <tuple>
#include <string>
#include <iostream>
int main() {
std::tuple<int, std::string, double> myTuple{10, "twenty", 30.5};
// 访问特定类型的元素
auto myString = std::get<std::string>(myTuple); // C++14 标准及以上
std::cout << "The string in the tuple is: " << myString << std::endl;
return 0;
}
std::tuple
是处理异构数据集合的一个非常有用的工具,它允许你将不同类型的数据组合成一个单一的对象,同时保持类型安全。它在多线程编程、数据打包和函数返回多个值时特别有用。
16、空间划分:
std::queue
std::queue
是一个遵循先进先出(FIFO)原则的容器。它只允许在一端(队尾)添加元素,在另一端(队首)移除元素。
#include <iostream>
#include <queue>
int main() {
std::queue<int> q;
// 添加元素到队列
q.push(1);
q.push(2);
q.push(3);
// 访问队首元素
std::cout << "Front element is: " << q.front() << std::endl;
// 移除队首元素
q.pop();
// 再次访问队首元素
std::cout << "Next front element is: " << q.front() << std::endl;
return 0;
}
std::priority_queue
std::priority_queue
是一个队列,其中每个元素都有一个优先级,并且元素的排序基于它们的优先级。默认情况下,元素是按最大值排序的,即队首总是最大元素。
#include <iostream>
#include <queue>
int main() {
std::priority_queue<int> pq;
// 添加元素到优先队列
pq.push(30);
pq.push(10);
pq.push(20);
// 访问队首元素(最大元素)
std::cout << "The highest priority element is: " << pq.top() << std::endl;
// 移除队首元素
pq.pop();
// 再次访问队首元素
std::cout << "Next highest priority element is: " << pq.top() << std::endl;
return 0;
}
std::stack
std::stack
是一个遵循后进先出(LIFO)原则的容器。它只允许在一端(栈顶)添加和移除元素。
#include <iostream>
#include <stack>
int main() {
std::stack<int> s;
// 添加元素到栈
s.push(1);
s.push(2);
s.push(3);
// 访问栈顶元素
std::cout << "Top element is: " << s.top() << std::endl;
// 移除栈顶元素
s.pop();
// 再次访问栈顶元素
std::cout << "New top element is: " << s.top() << std::endl;
return 0;
}
这些容器适配器提供了不同的数据结构抽象,允许你以特定的方式操作元素。std::queue
适用于需要保持元素顺序的场合,std::priority_queue
适用于需要根据元素的优先级进行排序的场合,而 std::stack
适用于需要后进先出处理的场合。每种适配器都通过限制容器的某些操作,提供了一种特定的行为模式。
17、配对(pair):
创建和初始化 std::pair
#include <utility> // std::pair 所在的头文件
int main() {
// 直接初始化
std::pair<int, double> p1(1, 3.14);
// 使用 make_pair 创建 pair 对象
std::pair<std::string, int> p2 = std::make_pair("example", 42);
return 0;
}
访问 std::pair
成员
#include <utility>
#include <iostream>
int main() {
std::pair<int, std::string> p(10, "example");
// 使用 first 和 second 成员函数访问 pair 中的元素
std::cout << "First element: " << p.first << std::endl;
std::cout << "Second element: " << p.second << std::endl;
return 0;
}
使用 std::pair
作为函数返回类型
#include <utility>
#include <iostream>
// 函数返回两个值的 pair 对象
std::pair<int, int> minMax(int a, int b) {
return std::make_pair((a < b) ? a : b, (a < b) ? b : a);
}
int main() {
auto result = minMax(5, 10);
std::cout << "Min: " << result.first << ", Max: " << result.second << std::endl;
return 0;
}
std::pair
在标准库容器中的使用
#include <utility>
#include <map>
#include <iostream>
int main() {
std::map<std::string, int> myMap;
// 使用 pair 向 map 中插入元素
myMap.insert(std::make_pair("apple", 1));
myMap.insert(std::make_pair("banana", 2));
// 访问 map 中的元素
for (const auto& pair : myMap) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
return 0;
}
std::pair
提供了一种方便的方式来组合两个相关联的值,并且由于其简单和灵活性,在 C++ 编程中得到了广泛的应用。
18、哈希表:
std::hash
std::hash
是一个函数对象,用于生成给定值的哈希值。这是无序容器背后的关键部分,因为它们使用哈希值来存储和查找元素。
#include <functional>
#include <iostream>
int main() {
int value = 42;
std::hash<int> hasher;
std::size_t hash_value = hasher(value);
std::cout << "Hash value of " << value << " is " << hash_value << std::endl;
return 0;
}
std::unordered_set
std::unordered_set
是一个无序容器,它存储唯一元素的集合,并保证快速查找。
#include <unordered_set>
int main() {
std::unordered_set<int> uset = {1, 2, 3, 4, 5};
// 插入元素
uset.insert(6);
// 访问元素
for (int num : uset) {
std::cout << num << ' ';
}
std::cout << std::endl;
return 0;
}
std::unordered_map
std::unordered_map
是一个无序容器,它存储键值对,并且保证每个键是唯一的。
#include <unordered_map>
int main() {
std::unordered_map<char, std::string> umap = {{'a', "apple"}, {'b', "banana"}};
// 插入键值对
umap['c'] = "cherry";
// 访问键值对
for (const auto& pair : umap) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
return 0;
}
std::unordered_multiset
std::unordered_multiset
类似于 std::unordered_set
,但它允许容器中存在相同元素的多个副本。
#include <unordered_set>
int main() {
std::unordered_multiset<int> ums = {1, 2, 2, 3, 4};
// 插入元素
ums.insert(2); // 允许插入重复的元素
// 遍历元素
for (int num : ums) {
std::cout << num << ' ';
}
std::cout << std::endl;
return 0;
}
std::unordered_multimap
std::unordered_multimap
类似于 std::unordered_map
,但它允许容器中存在具有相同键的多个元素。
#include <unordered_map>
int main() {
std::unordered_multimap<std::string, int> umm;
umm.insert({"apple", 1});
umm.insert({"banana", 2});
umm.insert({"apple", 3}); // 允许插入具有相同键的元素
// 遍历键值对
for (const auto& pair : umm) {
std::cout << pair.first << " -> " << pair.second << std::endl;
}
return 0;
}
无序容器的效率很高,特别是当涉及到大量数据时。它们通常比有序容器(如 std::set
、std::map
)更快地进行插入和查找操作,因为它们不需要维护元素的排序。然而,无序容器中的元素不保证以任何特定的顺序排列。
19、内存操作:
std::allocator
std::allocator
是一个模板类,用于定义对象的内存分配和释放策略。它通常与标准容器(如 std::vector
、std::map
)一起使用,但也可以自定义以满足特定的内存管理需求。
#include <memory>
#include <iostream>
int main() {
// 使用 std::allocator 分配和释放内存
std::allocator<int> alloc;
int* ptr = alloc.allocate(1); // 分配一个 int 的内存
alloc.construct(ptr, 42); // 构造一个 int 对象
std::cout << "Allocated int: " << *ptr << std::endl;
alloc.destroy(ptr); // 销毁对象
alloc.deallocate(ptr, 1); // 释放内存
return 0;
}
std::unique_ptr
std::unique_ptr
是一种智能指针,它拥有并管理动态分配的资源。它确保同一时间只有一个 std::unique_ptr
实例拥有资源,当 std::unique_ptr
离开作用域时,资源会自动被释放。
#include <memory>
#include <iostream>
class Resource {
public:
Resource() { std::cout << "Resource created." << std::endl; }
~Resource() { std::cout << "Resource destroyed." << std::endl; }
};
int main() {
std::unique_ptr<Resource> resource(new Resource()); // 创建并自动管理 Resource 对象
// 不需要显式删除资源,当 unique_ptr 离开作用域时自动销毁
return 0;
}
std::shared_ptr
std::shared_ptr
是另一种智能指针,它通过引用计数机制管理资源。多个 std::shared_ptr
实例可以共享同一资源,资源会在最后一个引用它的 std::shared_ptr
被销毁或被赋值为空时自动释放。
#include <memory>
#include <iostream>
int main() {
std::shared_ptr<Resource> resource1(new Resource());
std::shared_ptr<Resource> resource2 = resource1; // resource1 和 resource2 共享 Resource 对象
// 当 resource1 和 resource2 都离开作用域时,引用计数归零,Resource 对象被销毁
return 0;
}
智能指针是C++中现代内存管理的核心部分,它们提供了自动内存管理的便利,同时避免了传统裸指针的许多常见陷阱,如内存泄漏和悬挂指针。正确地使用智能指针对于编写安全、健壮的C++程序至关重要。
20、类型特征(Type Traits):
std::is_arithmetic
检查类型是否是算术类型,即是否是整数类型或浮点数类型。
#include <type_traits>
#include <iostream>
int main() {
std::cout << std::boolalpha; // 打印布尔值时使用 boolalpha 格式化
std::cout << "is_arithmetic<double>: " << std::is_arithmetic<double>::value << std::endl; // true
std::cout << "is_arithmetic<std::string>: " << std::is_arithmetic<std::string>::value << std::endl; // false
return 0;
}
std::is_integral
检查类型是否是整型。
std::cout << "is_integral<char>: " << std::is_integral<char>::value << std::endl; // true
std::cout << "is_integral<float>: " << std::is_integral<float>::value << std::endl; // false
std::is_floating_point
检查类型是否是浮点数类型。
std::cout << "is_floating_point<double>: " << std::is_floating_point<double>::value << std::endl; // true
std::cout << "is_floating_point<int>: " << std::is_floating_point<int>::value << std::endl; // false
std::is_convertible
检查是否存在从类型 From
到类型 To
的转换。
std::cout << "is_convertible<int, double>: " << std::is_convertible<int, double>::value << std::endl; // true
std::cout << "is_convertible<double, int>: " << std::is_convertible<double, int>::value << std::endl; // false
std::is_pod
检查类型是否是 POD(Plain Old Data)类型,即是否是标准布局且没有类特定特性的类型。
struct PodType { int i; double d; };
struct NonPodType { virtual void f() {} };
std::cout << "is_pod<PodType>: " << std::is_pod<PodType>::value << std::endl; // true
std::cout << "is_pod<NonPodType>: " << std::is_pod<NonPodType>::value << std::endl; // false
std::is_enum
检查类型是否是枚举类型。
enum class Enum { Value };
struct NotEnum {};
std::cout << "is_enum<Enum>: " << std::is_enum<Enum>::value << std::endl; // true
std::cout << "is_enum<NotEnum>: " << std::is_enum<NotEnum>::value << std::endl; // false
std::is_class
检查类型是否是类类型(不是联合体,不是枚举,不是类类型)。
class MyClass {};
union MyUnion { int i; double d; };
std::cout << "is_class<MyClass>: " << std::is_class<MyClass>::value << std::endl; // true
std::cout << "is_class<MyUnion>: " << std::is_class<MyUnion>::value << std::endl; // false
std::is_function
检查类型是否是一个函数类型。
void function() {}
void (*functionPointer)() = &function;
std::cout << "is_function<function>: " << std::is_function<decltype(function)>::value << std::endl; // true
std::cout << "is_function<int>: " << std::is_function<int>::value << std::endl; // false
std::is_member_function_pointer
检查类型是否是一个指向成员函数的指针。
class MyClass {
public:
void memberFunction() {}
};
std::cout << "is_member_function_pointer<decltype(&MyClass::memberFunction)>: "
<< std::is_member_function_pointer<decltype(&MyClass::memberFunction)>::value << std::endl; // true
std::is_base_of
检查 Base
是否是 Derived
的基类或 Base
和 Derived
是相同的类型。
class Base {};
class Derived : public Base {};
class Unrelated {};
std::cout << "is_base_of<Base, Derived>: " << std::is_base_of<Base, Derived>::value << std::endl; // true
std::cout << "is_base_of<Base, Unrelated>: " << std::is_base_of<Base, Unrelated>::value << std::endl; // false
类型特征是C++11及以后版本中的一项重要特性,它们提供了一种在编译时检查和利用类型属性的方法。这使得编写的模板代码更加灵活和健壮。
21、概念(Concepts) (C++20):
C++20 引入了概念(concepts),这是一种新特性,用于定义类型必须满足的条件。std::same_as
、std::integral
、std::signed_integral
和 std::regular
是一些与概念相关的类型特征,它们提供了一种在编译时检查类型属性的方法。
std::same_as
std::same_as
是一个概念,用于检查两个类型是否完全相同。
#include <type_traits>
static_assert(std::same_as<int, int>); // 通过
static_assert(std::same_as<int, double>); // 失败,因为 int 和 double 是不同的类型
std::integral
std::integral
是一个概念,用于检查类型是否是整数类型。
#include <type_traits>
static_assert(std::integral<int>); // 通过,因为 int 是整数类型
static_assert(std::integral<double>); // 失败,因为 double 不是整数类型
std::signed_integral
std::signed_integral
是一个概念,用于检查类型是否是有符号整数类型。
#include <type_traits>
static_assert(std::signed_integral<signed char>); // 通过,因为 signed char 是有符号整数类型
static_assert(std::signed_integral<unsigned int>); // 失败,因为 unsigned int 是无符号整数类型
std::regular
std::regular
是一个概念,用于检查类型是否是正则类型。一个正则类型是指具有以下特性的类型:
- 具有默认构造函数
- 具有复制构造函数
- 具有移动构造函数
- 具有复制赋值运算符
- 具有移动赋值运算符
- 具有解引用运算符(当它是一个指针类型时)
#include <type_traits>
#include <utility>
class RegularClass {
public:
RegularClass() = default;
RegularClass(const RegularClass&) = default;
RegularClass(RegularClass&&) = default;
RegularClass& operator=(const RegularClass&) = default;
RegularClass& operator=(RegularClass&&) = default;
int& operator*() { return value; } // 示例解引用运算符
int value = 42;
};
static_assert(std::regular<RegularClass>); // 通过,因为 RegularClass 满足正则类型的定义
这些概念提供了一种在编译时检查类型属性的方法,它们是C++20中概念特性的一部分。使用这些概念,开发者可以编写出更安全、更健壮的模板代码,因为它们允许在编译时对类型进行严格的约束和检查。
22、文件系统(Filesystem) (C++17):
std::filesystem::path
std::filesystem::path
类表示文件系统中的路径。它可以用来创建、解析和组合文件路径。
#include <filesystem>
#include <iostream>
#include <string>
namespace fs = std::filesystem;
int main() {
fs::path p1 = "/usr/bin";
fs::path p2 = "/usr/local/bin";
fs::path combined = p1 / "somefile.txt"; // 路径连接
std::cout << "Path: " << combined << std::endl;
std::cout << "Parent path: " << combined.parent_path() << std::endl;
std::cout << "Filename: " << combined.filename() << std::endl;
// 检查路径是否存在
if (fs::exists(combined)) {
std::cout << "Path exists." << std::endl;
}
return 0;
}
std::filesystem::directory_entry
std::filesystem::directory_entry
类表示文件系统中的单个目录条目,它可以是文件或目录。
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
fs::directory_entry entry(".");
if (entry.exists()) {
std::cout << "Entry exists." << std::endl;
if (entry.is_regular_file()) {
std::cout << "It's a regular file." << std::endl;
} else if (entry.is_directory()) {
std::cout << "It's a directory." << std::endl;
}
} else {
std::cout << "Entry does not exist." << std::endl;
}
return 0;
}
std::filesystem::filesystem_error
std::filesystem::filesystem_error
是一个异常类,用于报告文件系统操作中的错误。
#include <filesystem>
#include <iostream>
#include <string>
namespace fs = std::filesystem;
int main() {
try {
fs::copy("source.txt", "destination.txt");
} catch (const fs::filesystem_error& e) {
std::cout << "Filesystem error: " << e.what() << std::endl;
std::cout << "Error code: " << e.code() << std::endl;
}
return 0;
}
std::filesystem
库提供了一系列操作文件和目录的函数,包括创建、删除、移动、复制文件和目录,以及查询文件属性等。使用这些功能,开发者可以方便地进行文件系统编程,而无需依赖平台特定的API。
这些是 C++ 标准库中提供的部分模板类型的实例。C++ 标准库的设计哲学是为最广泛的使用情况提供支持,因此它包含了很多不同的模板类和函数,以适应各种不同的编程需求。随着 C++ 语言的不断发展,标准库也在逐渐扩展,引入新的模板类型以支持更多的编程模式和用例。
这些模板类型是 C++ 标准库的核心部分,它们提供了广泛的功能,从容器管理到算法实现,再到并发编程和异常处理,极大地丰富了 C++ 的编程能力。