# 十三、C++ 标准库

## 简介

C++ 标准库中的内容比我们有时间讨论的要多得多。我们将只关注一些我们还没有探索过的最常用的特性。

## 迭代器

迭代器的作用与 IEnumerable 和中的相关接口相同。NET，例如提供一种在集合中导航的通用方法。例如，给定一个`std::vector`，您可以使用以下代码循环遍历它的项目集合:

```cpp
          vector<int> vec;
          vec.push_back(1);
          vec.push_back(4);
          vec.push_back(7);
          vec.push_back(12);
          vec.push_back(8);

          for (auto i = begin(vec); i != end(vec); i++)
          {
                wcout << *i << endl;
          }

```

`std::begin`函数提供了一个指向集合第一项的迭代器。`std::end`提供一个迭代器，表示我们已经到达集合的末尾；集合的最后一个项目，假设集合中有任何项目，是`std::end`给我们的项目之前的一个项目。这就是为什么我们在`for`循环中检查`!=`。如果集合中没有项目，则`std::begin`和`std::end`将返回相同的值。

除了这两个模板函数的迭代器之外，许多集合还通过名为`cbegin`和`cend`的成员函数提供`const`迭代器，通过`rbegin`和`rend`提供反向迭代器(反向循环遍历集合)，通过`crbegin`和`crend`提供`const`反向迭代器。在前面的例子中，你可以用`vec.rbegin()`替换`begin(vec)`，用`vec.rend()`替换`end(vec)`，反向遍历向量。

## 基于范围的`for`循环

C++ 11 增加了一种额外类型的`for`循环，称为基于范围的`for`循环，它提供的功能类似于 C# 中的`foreach`循环。基于范围的`for`循环使用迭代器，省去了去引用指针的麻烦，也省去了错误检查结束的可能性。基于范围的`for`循环相当于前面示例中的`for`循环，如下所示:

```cpp
          for (auto item : vec)
          {
                wcout << item << endl;
          }

```

## `std::vector`和其他容器

你最有可能使用的收藏是`std::vector`。它是一个快速的通用集合，类似于. NET 中的`List<T>`，可以在`<vector>`头文件中找到。

要在向量末尾添加一个项目，使用成员函数`push_back`。要从向量末尾移除一个项目，请使用`pop_back`。您可以像访问数组一样，使用`[]`访问索引处的项目。要在特定的从零开始的索引处添加元素或元素范围，请使用`insert`成员函数。要删除特定从零开始的索引处的元素或元素范围，请使用`erase`成员函数。

C++ 11 中增加的一个简洁特性是`emplace`和`emplace_back`成员函数提供的就地构造功能。与其构造一个对象，然后使用`insert`或`push_back`将其添加到向量中，不如调用`emplace_back`并简单地将传递给构造器的参数传递给向量持有的类型。然后，该向量将构建并添加一个新的对象实例，而不需要进行复制或移动带来的额外计算，也不需要使用额外的本地内存。

`emplace`函数的工作原理是一样的，除了你首先给它传递一个指定位置的迭代器。您可以使用`cbegin()`或`cend()`向矢量的开头或结尾添加项目。如果你有一个特定的从零开始的索引想要放置一个物品，你可以使用`vec.cbegin() + idx`。如果你想在一个项目的末尾放置一些空格，你也可以从`cend()`中减去。

`vector`提供了更多的功能，所以你肯定应该进一步探索。例如，`at`成员函数会在索引处给你一个项目。有一些方法可以告诉向量调整它的内部容量，这样你就有更多的空闲空间——例如，如果你知道你需要正好 125 个项目——或者这样你就最小化了内存使用——如果你添加了它将需要的所有元素并且内存限制很紧。

除了`std::vector`，几个类似的容器有不同的用例。`std::vector`当您需要极其快速、随机的访问时，它本身就是最佳选择，因为您通常会在集合的最末端添加和删除项目。如果你也需要经常在收藏前添加物品，可以考虑使用`std::deque`代替。

先入先出容器使用`std::queue`。使用`std::stack`作为后进先出容器。

`std::map`类提供了一个排序的字典。`std::unordered_map`提供哈希表。

`std::set`类是一个排序的键控集合，其中存储的项是它自己的键，因此每个元素必须是唯一的。`std::unordered_set`是`std::set`的未排序的等价物。

`std::list`类提供了一个双向链表。`std::forward_list`提供单链表。

## `<algorithm>`表头

`<algorithm>`表头包含了很多非常有用的功能:比如`find`、`sort`、`copy`之类的东西，以及它们所有的相关方法。学习它们的最好方法是用它们做实验。

## C 运行时库

C 运行时库中的一些功能可能很有用。一般来说，访问库最好的方式就是包含相关的`<c_____>`头文件，比如`<cstdlib>`。