C++ STL标准库中模板类型

目录

1、容器(Containers):

1. std::vector

2. std::deque

3. std::array

4. std::list

5. std::forward_list

6. std::set

7. std::map

8. std::multiset

9. std::multimap

10. std::unordered_set

11. std::unordered_map

12. std::unordered_multiset

13. std::unordered_multimap

2、迭代器(Iterators)

输入迭代器(std::istream_iterator)

输出迭代器(std::ostream_iterator)

反向迭代器(reverse_iterator)

std::move_iterator

3、算法(Algorithms)

非修改性序列算法

修改性序列算法

排序算法

二分算法

集合算法

堆算法

随机算法

4、函数对象(Functional)

std::plus<>: 用于执行加法运算。

std::minus<>: 用于执行减法运算。

std::multiplies<>: 用于执行乘法运算。

std::divides<>: 用于执行除法运算。

std::negate<>: 用于对数值取反。

std::equal_to<>: 用于比较两个值是否相等。

std::not_equal_to<>: 用于比较两个值是否不相等。

std::greater<>: 用于比较两个值,判断第一个值是否大于第二个值。

std::less<>: 用于比较两个值,判断第一个值是否小于第二个值。

std::logical_and<>: 用于逻辑与操作。

std::logical_or<>: 用于逻辑或操作。

std::bit_and<>: 用于按位与操作。

5、输入/输出(I/O):

std::iostream:

std::istream:

std::ostream:

std::stringstream:

std::wiostream, std::wistream, std::wostream:

6、字符串和文本处理:

std::string:

std::wstring:

std::u16string:

std::u32string:

7、数值操作:

8、动态内存管理:

std::unique_ptr:

std::shared_ptr:

std::weak_ptr:

9、异常:

std::exception:

std::runtime_error:

std::invalid_argument:

10、线程支持:

std::thread:

std::mutex:

std::recursive_mutex:

std::lock_guard:

std::unique_lock:

11、原子操作:

 std::atomic:

std::atomic_bool:

std::atomic_char:

std::atomic_schar:

std::atomic_uchar:

12、时间日期:

std::chrono::system_clock:

std::chrono::steady_clock:

std::chrono::high_resolution_clock:

std::chrono::duration:

std::chrono::time_point:

13、智能指针:

std::unique_ptr

std::shared_ptr

std::weak_ptr

14、正则表达式:

std::regex

std::match_results

std::regex_iterator

std::regex_token_iterator

15、元组(Tuples):

创建和初始化 std::tuple

访问 std::tuple 元素

使用 std::tie 存储多个变量到 std::tuple

使用 std::apply 应用函数到 std::tuple 元素

使用 std::get 访问特定类型的元素

16、空间划分:

std::queue

std::priority_queue

std::stack

17、配对(pair):

创建和初始化 std::pair

访问 std::pair 成员

使用 std::pair 作为函数返回类型

std::pair 在标准库容器中的使用

18、哈希表:

std::hash

std::unordered_set

std::unordered_map

std::unordered_multiset

std::unordered_multimap

19、内存操作:

std::allocator

std::unique_ptr

std::shared_ptr

20、类型特征(Type Traits):

std::is_arithmetic

std::is_integral

std::is_floating_point

std::is_convertible

std::is_pod

std::is_enum

std::is_class

std::is_function

std::is_member_function_pointer

std::is_base_of

21、概念(Concepts) (C++20):

std::same_as

std::integral

std::signed_integral

std::regular

22、文件系统(Filesystem) (C++17):

std::filesystem::path

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>头文件提供了一组函数对象,它们是作为模板参数传递的函数的特化形式。这些函数对象可以像函数一样使用,但它们是对象,因此可以拥有状态(例如,成员变量)和/或行为(例如,成员函数)。这些函数对象常用于标准库算法中,以提供自定义的比较或运算逻辑。

  1. 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
    
  2. 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
    
  3. 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
    
  4. 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
    
  5. 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
    }
    
  6. 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
    }
    
  7. std::not_equal_to<>: 用于比较两个值是否不相等。

    auto it2 = std::find_if(v.begin(), v.end(), std::not_equal_to<>());
    // 这个例子可能需要更多的上下文来展示,因为not_equal_to需要两个参数
    
  8. std::greater<>: 用于比较两个值,判断第一个值是否大于第二个值。

    std::sort(v.begin(), v.end(), std::greater<>());
    for (int i : v) {
      std::cout << i << " "; // 输出 5 4 3 2 1
    }
    
  9. std::less<>: 用于比较两个值,判断第一个值是否小于第二个值。

    std::sort(v.begin(), v.end(), std::less<>());
    for (int i : v) {
      std::cout << i << " "; // 输出 1 2 3 4 5
    }
    
  10. 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
    }
    
  11. std::logical_or<>: 用于逻辑或操作。

    // 类似于logical_and,需要更多的上下文来展示
    
  12. 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::istreamstd::ostream的公共基类,允许进行输入和输出操作。std::cinstd::coutstd::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::wiostreamstd::wistreamstd::wostream:


这些类是宽字符版本的输入输出流类,用于处理宽字符(如Unicode字符)。它们允许程序以统一的方式处理国际化的文本。

#include <wiostream>

int main() {
    std::wcout << L"Hello, World!" << std::endl; // 使用宽字符输出流
    return 0;
}

请注意,宽字符流的使用在实际编程中不如单字节流常见,因为它们主要用于处理需要国际化支持的程序。在大多数英文环境下,使用std::iostreamstd::istreamstd::ostream已经足够。

6、字符串和文本处理:

在C++中,std::stringstd::wstringstd::u16stringstd::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_errorstd::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_argumentstd::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_lockstd::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 是一个模板类,用于表示时间间隔。它需要两个模板参数:第一个是用于表示持续时间的类型(通常是 intlong 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::setstd::map)更快地进行插入和查找操作,因为它们不需要维护元素的排序。然而,无序容器中的元素不保证以任何特定的顺序排列。

19、内存操作:

std::allocator

std::allocator 是一个模板类,用于定义对象的内存分配和释放策略。它通常与标准容器(如 std::vectorstd::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_asstd::integralstd::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++ 的编程能力。

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值