简介

  • C++ 标准库

pair工具类

  • pair在头文件中定义,并将两个可能属于不同类型的值组合起来。可以通过first和second公共数据成员访问这两个值
  • 在C++17引入对CTAD的支持之前,可以使用std::make_pair()工具函数模板,从两个值构造一个pair

C++ 标准库

<utility> 是 C++ 标准库中的头文件,它包含了一些实用工具和通用功能,提供了一些模板类和函数。这个头文件定义了一些基本的工具类和函数,以支持各种通用编程需求。

以下是 <utility> 头文件中一些常见的功能和类:

1. std::pair

  • std::pair 是一个模板类,用于存储一对值,类似于键值对的概念。
  • 通常用于函数返回多个值或存储两个相关的值。

2. std::make_pair

  • std::make_pair 是一个模板函数,用于创建一个 std::pair 对象。
  • 接受两个参数,自动推导类型并返回一个 std::pair 对象。

3. std::move

  • std::move 是一个函数模板,用于将对象转移到新位置,通常与移动语义一起使用。
  • 将对象转换为右值引用,以便在赋值后对象的状态可以改变,而不是复制。

4. std::forward

  • std::forward 是一个函数模板,用于完美转发(perfect forwarding)。
  • 用于在函数模板中保留参数的引用类型,使其继续保持右值或左值属性。

5. 其他工具和函数

  • <utility> 还包含其他一些小的工具函数和模板,比如 std::swap 用于交换两个值,以及一些用于元组访问和元编程的功能。

这些工具和类都是用于提供一些通用的功能,可以在许多不同的情况下使用,从简单的值对存储到高级的模板转发等。

C++ 标准库 详解

<utility> 是 C++ 标准库中的头文件,提供了一些通用工具、类模板和函数,用于各种编程场景中的通用操作和工具性功能。以下是 <utility> 中一些主要的功能和类的详细解释:

1. std::pair

  • std::pair 是一个模板类,用于存储一对值,即将两个值组合成一个对象。
  • 通常用于函数返回多个值或需要将两个相关联的值作为一个单元处理的情况。
  • 示例:
    1
    
    std::pair<int, std::string> myPair = std::make_pair(42, "Hello");
    

2. std::make_pair

  • std::make_pair 是一个模板函数,用于创建 std::pair 对象。
  • 它接受两个参数并自动推导类型,并返回一个对应类型的 std::pair 对象。
  • 示例:
    1
    
    auto myPair = std::make_pair(42, "Hello");
    

3. std::move

  • std::move 是一个函数模板,用于将一个左值转换为对应的右值引用。
  • 通常用于支持移动语义,在移动语义中,资源的所有权可以从一个对象转移到另一个对象,而无需进行深层复制。
  • 示例:
    1
    2
    
    std::string str1 = "Hello";
    std::string str2 = std::move(str1); // Move str1 to str2
    

4. std::forward

  • std::forward 是一个模板函数,用于完美转发(perfect forwarding)。
  • 通常在泛型编程中用于传递参数,并保持参数的原始左值或右值特性。
  • 主要用于在泛型函数或模板中保留参数的原始引用类型。
  • 示例:
    1
    2
    3
    4
    
    template <typename T>
    void wrapper(T&& arg) {
        some_function(std::forward<T>(arg));
    }
    

5. std::swap

  • std::swap 是一个函数模板,用于交换两个对象的值。
  • 适用于大多数基本类型以及用户自定义类型的交换操作。
  • 示例:
    1
    2
    
    int a = 5, b = 10;
    std::swap(a, b); // Swap values of a and b
    

这些功能和类提供了通用的工具和操作,可用于各种不同的情况,从简单的值对组合到高级的模板转发。它们是 C++ 标准库提供的一些核心工具,为编写高效、通用的代码提供了便利。

C++ 标准库 常用的类和函数

<utility> 标准库提供了一些常用的类和函数,以下是其中一些主要的类和函数:

1. std::pair

  • std::pair 是一个模板类,用于存储一对值(通常是不同类型的值),将两个值作为一个单元存储和访问。
  • 示例:
    1
    
    std::pair<int, std::string> myPair = std::make_pair(42, "Hello");
    

2. std::make_pair

  • std::make_pair 是一个模板函数,用于创建 std::pair 对象,根据传递的参数类型自动推导 std::pair 对象的类型。
  • 示例:
    1
    
    auto myPair = std::make_pair(42, "Hello");
    

3. std::move

  • std::move 是一个函数模板,用于将左值转换为对应的右值引用,支持移动语义。
  • 用于支持移动语义,提高资源的有效使用。
  • 示例:
    1
    2
    
    std::string str1 = "Hello";
    std::string str2 = std::move(str1); // Move str1 to str2
    

4. std::forward

  • std::forward 是一个模板函数,用于完美转发(perfect forwarding)。
  • 在泛型编程中用于传递参数,并保持参数的原始左值或右值特性。
  • 示例:
    1
    2
    3
    4
    
    template <typename T>
    void wrapper(T&& arg) {
        some_function(std::forward<T>(arg));
    }
    

5. std::swap

  • std::swap 是一个函数模板,用于交换两个对象的值。
  • 适用于大多数基本类型以及用户自定义类型的交换操作。
  • 示例:
    1
    2
    
    int a = 5, b = 10;
    std::swap(a, b); // Swap values of a and b
    

这些类和函数是 <utility> 头文件中最常用的,提供了许多方便的工具和功能,用于各种不同的编程场景中。使用它们可以简化代码,提高效率,并且支持泛型编程范式。

std::pair

std::pair 是 C++ 标准库中的模板类,用于存储一对值。这两个值可以是不同类型的,通过 std::pair 可以将它们组合成一个单元,方便地对这两个值进行操作和传递。

特点和用途:

  • 存储一对值: std::pair 允许存储两个值,可以是不同的类型。
  • 多用于函数返回值: 常用于函数需要返回两个值时,可以将这两个值打包成一个 std::pair 返回。
  • 作为映射容器的值类型: 在某些情况下,用于作为键值对存储在映射容器(如 std::map)中。

基本用法示例:

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include <utility>

int main() {
    std::pair<int, std::string> myPair(42, "Hello");
    
    std::cout << "First value: " << myPair.first << std::endl;   // 访问第一个值
    std::cout << "Second value: " << myPair.second << std::endl; // 访问第二个值

    return 0;
}

主要成员函数:

  • firstsecond 分别用于访问存储的第一个值和第二个值。
  • make_pair 用于创建 std::pair 对象。
  • operator==operator!= 用于比较两个 std::pair 对象是否相等或不相等。

std::pair 提供了一种便捷的方式来存储和操作一对值,特别是在函数需要返回多个值时,可以将这些值捆绑成一个 std::pair 返回,提高了代码的可读性和简洁性。

std::make_pair()

std::make_pair() 是一个模板函数,用于创建 std::pair 对象。它接受两个参数,并根据这两个参数的类型自动推导出 std::pair 对象的类型,然后返回这个新创建的 std::pair 对象。

主要特点和用途:

  • 自动类型推导: std::make_pair() 会根据传入的参数类型自动推导出返回的 std::pair 对象的类型。
  • 便捷性: 方便创建和初始化 std::pair 对象,尤其适用于函数返回值或作为容器中的元素。

基本用法示例:

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include <utility>

int main() {
    auto myPair = std::make_pair(42, "Hello");

    std::cout << "First value: " << myPair.first << std::endl;   // 访问第一个值
    std::cout << "Second value: " << myPair.second << std::endl; // 访问第二个值

    return 0;
}

在这个示例中,std::make_pair() 接受一个整数和一个字符串作为参数,然后自动推导并返回一个 std::pair<int, const char*> 对象,将整数和字符串组合成一个对。这种自动推导减少了在代码中显式指定类型的需要,提高了代码的简洁性和可读性。

使用 std::make_pair() 可以方便地创建 std::pair 对象,并减少了手动指定模板参数的工作。

std::move

std::move 是 C++ 标准库中的一个函数模板,用于将给定的左值强制转换为右值引用。它并不实际移动任何数据,而是允许程序员表达对某个值的“移动语义”。

主要特点和用途:

  • 支持移动语义: std::move 是 C++11 引入的一个重要工具,用于支持右值引用和移动语义。
  • 避免不必要的复制: 可以使用 std::move 将左值转换为右值引用,从而避免不必要的复制操作,在移动语义下可以更有效地管理资源。
  • 用于移动语义: 通常与移动构造函数和移动赋值运算符一起使用,支持对资源的高效转移,如避免资源的深层复制。

基本用法示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <utility>
#include <string>

int main() {
    std::string str1 = "Hello";
    std::string str2 = std::move(str1); // 转移 str1 的内容到 str2
    
    std::cout << "str1 after move: " << str1 << std::endl; // 注意:此处 str1 可能已经为空
    std::cout << "str2 after move: " << str2 << std::endl;

    return 0;
}

在这个示例中,std::movestr1 转换为右值引用,允许将 str1 的内容有效地移动到 str2 中。移动操作不会复制数据,而是“窃取”了 str1 的资源,因此在输出 str1 的内容时,它可能为空。

注意: 使用 std::move 后,原来的左值变量(这里是 str1)可能不再包含有效的数据,因此需要谨慎使用移动语义,以避免悬空引用和使用无效数据。

std::forward

std::forward 是一个模板函数,通常与模板和引用折叠相关,用于完美转发(perfect forwarding)。

主要特点和用途:

  • 完美转发: 在泛型编程中,std::forward 用于在函数模板中正确地保持传递参数的值类别(左值或右值)。
  • 保留参数类型: 将传递给函数的参数的值类别(左值或右值)转发到另一个函数,以保留参数的原始引用类型。
  • 配合模板参数推导: 通常与函数模板一起使用,避免参数传递过程中的值类别转换。

基本用法示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <utility>

// 模拟一个函数模板,使用 std::forward 进行完美转发
template <typename T>
void wrapper(T&& arg) {
    some_function(std::forward<T>(arg));
}

int main() {
    int value = 42;
    wrapper(value); // 参数是左值
    wrapper(100);   // 参数是右值

    return 0;
}

在这个示例中,std::forward 用于将 wrapper 函数模板中的参数 arg 以原始的引用类型传递给 some_function。这有助于避免参数传递过程中的多余的值类别转换,实现完美转发,保持参数的原始引用类型。

std::forward 在实现泛型函数和模板函数时非常有用,可以正确地将参数的左值或右值特性转发给另一个函数,以实现参数值的有效传递。

std::swap()

std::swap() 是 C++ 标准库中的一个函数模板,用于交换两个对象的值。它可以用于大多数基本类型和用户自定义类型的对象交换操作。

主要特点和用途:

  • 交换值: std::swap() 允许交换两个对象的值,无论对象是基本类型还是自定义类型。
  • 泛型: 是一个泛型函数模板,适用于各种类型的对象交换。
  • 支持自定义类型: 对于自定义类型,需要实现该类型的 swap() 成员函数或者提供全局的 swap() 重载函数。

基本用法示例:

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <utility>

int main() {
    int a = 5, b = 10;
    std::swap(a, b); // 交换 a 和 b 的值

    std::cout << "a after swap: " << a << std::endl; // 输出已交换后的 a
    std::cout << "b after swap: " << b << std::endl; // 输出已交换后的 b

    return 0;
}

这个示例中展示了 std::swap() 函数如何交换两个整数变量 ab 的值。对于基本类型,std::swap() 能够直接进行交换操作,但对于自定义类型,需要提供相应的 swap() 函数实现。

对于自定义类型,通常应该提供一个 swap() 成员函数或全局的 swap() 重载函数,以实现该类型对象的交换操作,从而使 std::swap() 能够正确工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 例如,自定义类型的 swap() 函数实现:
class MyClass {
public:
    int value;
    // 自定义类型的 swap() 成员函数
    void swap(MyClass& other) {
        std::swap(value, other.value);
    }
};

namespace std {
    // 自定义类型的 swap() 全局重载函数
    void swap(MyClass& first, MyClass& second) {
        first.swap(second);
    }
}

通过提供适当的 swap() 函数,可以确保 std::swap() 在对自定义类型的对象进行交换时正常工作。