C++STL

标准模板库

主要来源:概述 | C++ STL Tutorial

容器

  • 容器:是一种可存储和管理对象集合的数据结构,直接实现了基本的数据存储和访问机制。例如,vector 是动态数组,list 是双向链表,set 是有序集合,unordered_map 是哈希表形式的键值对集合。 它们各自按照不同的数据结构原理,来组织和存储元素。
  • 容器适配器:是对已有的容器进行封装,改变其接口以满足特定的需求,本质上是一种包装器。它并不重新实现数据存储和管理机制,而是依赖于其他容器来完成这些工作。常见的容器适配器有 stack(栈)、queue(队列)、priority_queue(优先队列)。

容器:

flowchart TD G{"*指向元素的指针或迭代器,无论添加或删除元素,始终有效<br>**双向链接"} subgraph 序列容器 H{动态大小} H -- 否 --> array H -- 是 --> I{保持有序吗?} I -- 否 --> J{是否在中间插入/删除元素?} J -- 是 --> K{频繁遍历吗?} J -- 否 --> L{是否在前端插入/删除元素?} K -- 是 --> M{位置是否持久*?} K -- 否 --> N{大小变化大吗?} L -- 是 --> deque L -- 否 --> vector M -- 是 --> llist** N -- 否 --> vector N -- 是 --> llist** end subgraph 有序容器 I -- 是 --> O{主要用途?} O -- 中序遍历 --> P[vector<sorted> 或 flat_set] O -- 按键搜索 --> Q{允许重复元素吗?} Q -- 否 --> R{键映射到值吗?} Q -- 是 --> S{键映射到值吗?} R -- 是 --> map R -- 否 --> set S -- 是 --> multimap S -- 否 --> multiset end

容器适配器:

flowchart TD subgraph 自适应容器 A{顺序是否重要?} A -- 是 --> B{后进先出} A -- 否 --> C{先进先出} B -- 是 --> stack C -- 是 --> queue C -- 否 --> priority_queue end subgraph 无序容器 D{允许重复元素吗?} A -- 否 --> D D -- 否 --> E{键映射到值吗?} D -- 是 --> F{键映射到值吗?} E -- 是 --> unordered_map E -- 否 --> unordered_set F -- 是 --> unordered_multimap F -- 否 --> unordered_multiset end

注意点

对于vector,emplace_back有更好的性能,应当优先使用.

string_view在没有需要修改字符串的情况下,比如string更好

迭代器

const迭代器

简单说,const_iterator 是一种 "只读" 的迭代器,它指向的数据不能被修改。就像你只能看一个东西,但不能碰它。而普通的 iterator 是 "可写" 的,既能看也能改。

  • 防止意外修改数据(编译器会报错)

  • 让代码意图更清晰(别人一看就知道这里不会修改数据)

以前(C++98)这个 const_iterator 不好用,主要问题是:

  • 不容易创建(想从普通容器里拿到它很麻烦)
  • 很多操作不支持(比如想在找到的位置插入数据,C++98 不接受用 const_iterator 作为位置参数)

所以那时候大家宁可用普通 iterator,就算其实不需要修改数据。

从 C++11 开始,这些问题都解决了:

  • 容器新增了 cbegin()cend() 方法,直接就能拿到 const_iterator
  • 插入、删除等操作也支持用 const_iterator 来指定位置了

比如原来的代码可以改成这样(更简单且安全):

// 用 cbegin()/cend() 得到 const_iterator
auto it = std::find(values.cbegin(), values.cend(), 1983);
values.insert(it, 1998);  // 现在可以直接用 const_iterator 了

C++11 还有个小遗憾:对于一些特殊的数据结构(比如原生数组),没有提供全局的 cbegin()cend() 函数。C++14 补上了这个漏洞,让代码可以更通用。

总之:

  1. 写代码时,只要不需要修改迭代器指向的数据,就优先用 const_iterator
  2. 获取迭代器时,优先用 cbegin()cend()(而不是普通的 begin()end()
  3. 在通用代码中,优先用全局的 begin()end()cbegin() 等函数(而不是容器的成员函数)

这样做能让代码更安全、更清晰、更通用。

posted @ 2025-08-30 13:54  T0fV404  阅读(8)  评论(0)    收藏  举报