Stl容器问题

这个实验手册怎么样,是否需要进一步的丰富

这太棒了。我们将这两份内容的精华彻底融合,打造一份史诗级的《C++ STL 深度解剖实验手册》

这份手册采用了**【显微镜模式】(底层原理)【实战演练】(API与陷阱)**的双重架构。每一条都是一个独立的实验课题,请务必在 cgdb 中亲手验证。

实验环境配置(再次强调):

1
2
3
# 必须关闭优化 (-O0) 并开启调试信息 (-g)
g++ -g -O0 -std=c++17 main.cpp -o main
cgdb ./main

第一章:动态数组的霸主 —— std::vector

核心目标:掌握连续内存管理、扩容代价、对象生命周期。

【显微镜模式】(底层原理)

  1. 对象的骨架vector<int> v;。打印 sizeof(v)
    • GDB 验证:它通常等于 3 * sizeof(void*)(约24字节)。查看 p v,你能找到 _M_start, _M_finish, _M_end_of_storage 这三个指针吗?
  2. 栈与堆的分离vector 对象本身在栈上,数据在堆上。
    • GDB 验证:打印 &v&v[0]。两者的地址差值巨大说明了什么?
  3. 扩容的暴利:写循环 push_back,观察 v.capacity()
    • GDB 验证:它是按 1.5 倍(MSVC)还是 2 倍(GCC)增长的?
  4. 地址大迁徙:记录扩容前的 &v[0]。触发扩容后:
    • GDB 验证:旧地址里的数据还在吗?(查看 x/10wd 旧地址)。
    • 思考:这就是所有指向旧元素的迭代器/指针瞬间失效的物理原因。
  5. Size vs Capacity 的骗局push_back 100次后调用 v.clear()
    • GDB 验证size() 归零了,但 capacity() 变小了吗?内存真的释放给操作系统了吗?
    • 进阶:执行 v.shrink_to_fit() 后,再次观察 _M_start 地址是否改变?

【实战演练】(API & 坑点)

  1. 构造的歧义vector<int> v1(10, 5) vs vector<int> v2{10, 5}
    • GDB 验证p v1p v2 的内容分别是什么?(一个是10个5,一个是10和5)。
  2. 遍历删除的死亡陷阱:在 for 循环中 erase 偶数元素。
    • 代码:如果你写 v.erase(it); it++,程序会崩吗?
    • 修正:验证 it = v.erase(it) 的返回值是指向“下一个有效元素”的。
  3. Emplace 优化v.push_back(MyStruct(1,2)) vs v.emplace_back(1,2)
    • GDB 断点:在 MyStruct 的拷贝构造函数打断点。观察 emplace_back 是否成功避开了拷贝/移动构造?
  4. 访问安全v[1000] vs v.at(1000)
    • 行为观察:哪个导致 SIGSEGV(段错误,进程直接死掉),哪个抛出 std::out_of_range 异常(可以被 catch)?
  5. 插入效率:在 v.begin() 插入。
    • GDB 观察:打印 &v[1](原 v[0])。地址变了吗?说明了什么?(全员内存搬家)。

第二章:文本的特殊形态 —— std::string

核心目标:理解 SSO 优化、C 兼容性、只读视图。

【显微镜模式】(底层原理)

  1. SSO (短字符串优化)string s = "abc";
    • GDB 验证p (void*)s.data() 的地址是否落在了 &s 对象的范围内?(说明数据存在栈上,未分配堆内存)。
  2. SSO 临界点:不断 append 字符,直到长度超过 15 或 23(取决于编译器)。
    • GDB 验证:观察 s.data() 的地址何时突然跳变到堆区?
  3. 隐形的结束符string s = "abc";
    • GDB 验证x/4bc s.data()。虽然 size() 是 3,但你能看到第 4 个字节是 \0 吗?(为了兼容 C 接口)。
  4. 中间的 \0s += '\0'; s += "def";
    • GDB 验证p s.size() 是多少?p strlen(s.c_str()) 是多少?(理解 string 是“带长度的数组”,而 char* 依赖 \0)。
  5. Substr 的深拷贝string s2 = s1.substr(0, 5)
    • GDB 验证s2 的数据地址和 s1 有重叠吗?(验证它是全新的内存分配)。

【实战演练】(API & 坑点)

  1. 只读视图 std::string_view (C++17)string_view sv = s;
    • GDB 验证sizeof(sv) 只有 16 字节(指针+长度)。
    • 陷阱:让 s 发生扩容或销毁,再访问 sv,观察到了什么?(悬垂指针/UAF)。
  2. 查找失败的返回值size_t pos = s.find("xyz");
    • GDB 验证p pos 是 -1 吗?还是一个巨大的正整数?(验证 string::npos 的二进制表示)。
  3. 数值转换std::stoi("abc")
    • 行为观察:它会返回 0 还是抛出异常?

第三章:链式与分段 —— std::list & std::deque

核心目标:理解非连续内存、中控器、迭代器稳定性。

【显微镜模式】(底层原理)

  1. Deque 的中控器deque 插入大量数据。
    • GDB 验证&d[0]&d[size-1] 的距离等于 size * 4 吗?(绝不相等)。
    • 结构探索:尝试在 GDB 中找到 _M_map(二级指针数组)。
  2. List 的节点开销list<int> l;
    • GDB 验证x/4xg [节点地址]。除了存 int,还多了两个 8 字节的指针(prev/next)。计算内存膨胀率。
  3. 地址随机性:连续 push_back 3个元素进 List。
    • GDB 验证:它们的地址是连续的吗?(验证堆分配的随机性)。

【实战演练】(API & 坑点)

  1. 头插法的奇迹vector vs dequepush_front
    • GDB 验证deque 头部插入后,&d[1](原 d[0])的地址变了吗?(没变,说明 deque 只是开辟了新的“前驱块”,没有搬移数据)。
  2. List 的接合 (Splice)l1.splice(l1.end(), l2)
    • GDB 验证l2 变空了吗?l1 里的新节点地址变了吗?(指针操作,零拷贝,速度极快)。
  3. 迭代器失效对比
    • 场景:在中间插入元素。
    • 验证vector 的迭代器失效了吗?deque 的失效了吗?list 的失效了吗?(List 是唯一完全稳定的)。

第四章:树与哈希 —— std::map & std::unordered_map

核心目标:理解红黑树代价、哈希冲突、查找副作用。

【显微镜模式】(底层原理)

  1. 红黑树节点map<int, int> m;
    • GDB 验证:解引用迭代器 p *it。看到的类型是 pair<const int, int> 吗?
    • 结构:节点里藏了 _M_parent, _M_left, _M_right, _M_color。算算这一个节点多大?
  2. 哈希桶 (Bucket)unordered_map
    • GDB 验证:找到 _M_buckets 数组。
    • 冲突实验:构造哈希冲突的 Key 插入。观察它们是否在同一个 bucket 指针下挂成了链表?

【实战演练】(API & 坑点)

  1. [] 运算符的副作用cout << map["不存在的key"];
    • GDB 验证p map.size() 从 0 变成 1 了吗?
    • 思考:只想查询不想插入时,应该用什么?(find()at())。
  2. Key 的不可变性:尝试 it->first = 10
    • 验证:编译报错了吗?如果强行用指针改内存,树的结构会崩坏吗?(有序性丢失)。
  3. 自定义 Key
    • 代码:用 struct 做 Key。map 需要重载 <unordered_map 需要重载 == 并提供 hash 函数。缺一个会怎样?
  4. 性能退化:攻击哈希表。
    • 场景:让所有 Key 哈希冲突。查找速度退化为 O(N) 了吗?

第五章:容器适配器 —— std::stack / std::queue

核心目标:理解封装、底层替换、异常安全。

  1. 换个心脏stack<int, vector<int>> s;
    • GDB 验证ptype s。看到底层变成 vector 了吗?
  2. 受限访问
    • GDB 验证:虽然代码不能写 s[0],但 GDB 可以 p s.c[0] 偷看数据吗?
  3. Pop 的返回值:为什么 pop() 返回 void 而不是元素值?
    • 思考:如果返回元素时发生拷贝异常,元素是不是就永久丢失了?(理解异常安全性的设计)。
  4. 清空栈:Stack 没有 clear()
    • 代码:如何最快清空?验证 s = stack<int>()while(!s.empty()) s.pop()

终极实验:手写 Vector 的设计蓝图

设计挑战:完成上述实验后,尝试回答:

  1. 设计题:如果让你用 C 语言手写一个 vector
    • 你的结构体包含哪 3 个字段?
    • 你的 push_back 第一行代码是在检查什么?(Capacity)。
    • 扩容时,你会用 realloc 还是 malloc + memcpy?(提示:对于 C++ 对象,memcpy 是非法的,必须调用移动构造)。

按照这 35 个问题走下来,你看到的将不再是枯燥的代码,而是内存中流动的字节和指针的舞蹈。祝你在 GDB 的世界里探索愉快!

好的,这里是针对 C++ STL 常用容器的底层实现、方法应用、性能陷阱和现代 C++ 特性的 100 个深度问题。这些问题旨在考察开发者对 STL 的理解深度,而不仅仅是停留在“会用”的层面。

问题分为以下几个类别:

  1. 通用概念与容器对比 (1-15)
  2. std::vector (16-30)
  3. std::list & std::forward_list (31-40)
  4. std::deque (41-50)
  5. 有序关联容器 (map, set) (51-65)
  6. 无序关联容器 (unordered_map, unordered_set) (66-80)
  7. 容器适配器 (stack, queue, priority_queue) (81-85)
  8. 高级主题 (迭代器, 内存, 异常, 并发) (86-100)

一、通用概念与容器对比 (1-15)

  1. 迭代器失效 (Iterator Invalidation):请分别解释在对 std::vector, std::list, std::deque, std::unordered_map 进行插入(insert)和删除(erase)操作时,会导致哪些类型的迭代器、指针和引用失效?为什么?
  2. 性能权衡:在“随机访问”、“在序列中间插入/删除”和“在序列两端插入/删除”这三个场景下,请详细对比 vector, list, deque 的时间复杂度,并解释其底层数据结构如何导致这些性能差异。
  3. 缓存友好性 (Cache Friendliness):为什么通常说 std::vector 是缓存友好的,而 std::list 不是?这在实际应用中会带来多大的性能影响?请举例说明。
  4. emplace vs insert/pushemplace*系列方法(如 emplace_back, emplace)相比于 insertpush_back 的主要优势是什么?请解释其背后的完美转发(Perfect Forwarding)和原地构造(In-place Construction)机制。
  5. 节点式容器 vs 序列式容器:从内存分配和布局的角度,比较节点式容器(如 list, map)和序列式容器(如 vector, deque)的优缺点。
  6. map::operator[] vs map::atstd::mapoperator[]at() 方法有何区别?在什么情况下应该优先使用哪一个?operator[]mapped_type(值类型)有什么特殊要求?
  7. 有序 vs 无序:在选择键值对存储时,你会在什么情况下选择 std::map 而不是 std::unordered_map?请至少列出三个决定性因素。
  8. 异常安全保证 (Exception Safety Guarantee):STL 容器通常提供哪几种异常安全保证(基本、强、不抛出)?请以 vector::push_back 为例,说明当元素类型的拷贝/移动构造函数抛出异常时,容器会处于什么状态?
  9. 存储指针 vs 存储对象:在容器中直接存储对象(vector<MyObject>)与存储对象的智能指针(vector<unique_ptr<MyObject>>)各有什么优缺点和适用场景?
  10. size() vs capacity() vs max_size():解释 vector(或其他适用容器)中这三个函数的含义和区别。
  11. 清除容器clear() 方法和 c = {}(例如 v = {})在清空一个容器时,行为上有什么潜在的差异?(提示:考虑内存)
  12. shrink_to_fit()shrink_to_fit() 的作用是什么?为什么标准规定它是一个“非绑定请求”(non-binding request)?
  13. 多重容器 (Multi-containers)std::multimapstd::multiset 解决了什么问题?它们的底层实现与对应的 mapset 有何不同?
  14. C++17 的异构查找 (Heterogeneous Lookup):C++17 中,如何实现在 std::map<std::string, T> 中使用 std::string_view 进行查找而无需构造 std::string?这需要用到什么特性?
  15. 选择合适的容器:设计一个日志系统,需要频繁在尾部追加日志条目,偶尔需要按时间戳范围查找日志。你会选择哪个或哪些 STL 容器组合来实现?并说明原因。

二、std::vector (16-30)

  1. 动态增长策略std::vector 的容量在空间不足时是如何增长的?为什么通常采用“倍增”(或 1.5 倍)策略,而不是线性增加(如每次增加 10个元素)?
  2. reserve() 的重要性:在什么场景下,预先调用 reserve() 会极大地提升性能?它如何避免不必要的性能开销?
  3. vector<bool> 特化std::vector<bool> 是一个“假的”容器吗?请解释它的特殊底层实现(位集),以及这种实现带来的优点和哪些违反常规容器语义的“坑”?
  4. 移动语义与 vector:C++11 的移动语义(Move Semantics)如何优化 std::vector 的重分配(reallocation)过程?特别是当元素类型是 std::stringstd::unique_ptr 时。
  5. erase-remove 惯用法:请解释并实现 C++ 中的 “erase-remove idiom”。为什么直接循环调用 erase 来删除多个元素效率低下?
  6. 指针失效的细节:当 vector 发生重分配时,为什么指向其元素的“所有”指针、引用和迭代器都会失效?
  7. data() 方法v.data() 返回的指针有什么用?它与 &v[0] 有什么异同?在 C++11 之前和之后有什么变化?
  8. emplace_back 的异常安全:如果 emplace_back 的参数构造函数抛出异常,vector 的状态会怎样?它是否满足强异常安全保证?
  9. vector 插入操作的复杂度:为什么在 vector 的末尾插入是“摊还 O(1)”,而在开头或中间插入是 O(N)?请解释“摊还”的含义。
  10. noexcept 的移动构造函数:如果一个类型的移动构造函数没有被标记为 noexceptvector 在扩容时会如何处理?这会带来什么性能影响?

三、std::list & std::forward_list (31-40)

  1. list::size() 的历史:为什么在 C++11 之前,一些标准库实现的 list::size() 的时间复杂度是 O(N)?这与 splice 方法有什么关系?
  2. splice 的威力list::splice() 操作为什么效率极高(O(1))?请描述它的作用和底层实现原理。
  3. list vs. forward_liststd::forward_list 相比 std::list 有哪些优势和劣势?为什么它的 API 设计中充满了 *_after 形式的方法?
  4. 自我排序:为什么 std::liststd::forward_list 拥有自己的 sort() 成员函数,而 vectordeque 却使用全局的 std::sort()?(提示:迭代器类别)
  5. 内存开销:详细分析 std::list<T> 相对于 std::vector<T> 的内存开销。除了数据 T 本身,每个元素还需额外存储什么?
  6. 迭代器稳定性:为什么说 std::list 提供了最强的迭代器稳定性?除了被删除的那个元素,任何插入或删除操作都不会使指向其他元素的迭代器失效。
  7. list 的适用场景:在现代 C++ 编程中,考虑到缓存性能的影响,std::list 的实际适用场景还有哪些?
  8. 合并两个有序 list:如何高效地(优于 O(N log N))合并两个已排序的 std::list
  9. forward_listbefore_beginforward_listbefore_begin() 迭代器有什么特殊用途?为什么需要它?
  10. 实现 list::reverse:如果不使用 list::reverse() 成员函数,请描述如何原地反转一个 std::list,并分析其复杂度。

四、std::deque (41-50)

  1. deque 的底层结构:请详细描述 std::deque 的典型底层数据结构(“分块数组”或“中控数组”)。
  2. deque 的迭代器std::deque 的迭代器是如何实现的?为什么它能表现得像一个随机访问迭代器,但其内部结构却比 vector 的指针复杂得多?
  3. 性能特点deque 如何做到在两端进行摊还 O(1) 的插入和删除?它的随机访问为什么比 vector 慢?
  4. 迭代器失效的复杂性deque 的插入/删除操作导致的迭代器失效规则比 vector 更复杂。请具体说明在 deque 中间插入/删除元素时,哪些迭代器、指针和引用会失效,哪些不会。
  5. 内存布局deque 的元素在内存中是连续的吗?这对其性能有什么影响?
  6. deque vs. vector:如果一个场景需要频繁在容器头部插入元素,deque 是唯一的选择吗?和 vector 相比,除了头部插入,它还有什么优势?(例如,不会发生一次性的大规模内存复制)
  7. deque 的收缩deque 是否支持 shrink_to_fit()?其效果与 vector 有何不同?
  8. 作为底层容器:为什么 std::stackstd::queue 默认使用 std::deque 作为其底层容器,而不是 std::vectorstd::list
  9. 指针与引用:在 deque 的两端进行插入操作后,指向未受影响元素的指针和引用是否保持有效?为什么?
  10. 小对象存储:对于存储大量小对象,deque 的分块结构相比 vector 的连续内存,在内存管理上可能有什么优势?

五、有序关联容器 (map, set) (51-65)

  1. 底层实现std::mapstd::set 通常基于哪种自平衡二叉搜索树?为什么选择它而不是 AVL 树?
  2. Key 的要求:作为 std::mapstd::set 的键(Key),类型必须满足什么要求?(提示:Compare 函数对象)
  3. lower_bound vs upper_bound:请解释 map::lower_boundmap::upper_bound 的作用和区别。如何利用它们高效地对 map 进行范围查询?
  4. 迭代顺序:遍历一个 std::mapstd::set 时,元素的顺序是如何保证的?
  5. 插入操作的返回值map::insert 的返回值是什么类型?它包含了哪些信息?如何利用这些信息判断插入是否成功以及获取指向元素的迭代器?
  6. emplace 与提示 (hint)emplace_hint(iterator, args...) 中的 hint 参数有什么作用?在什么情况下它能将插入操作的复杂度从 O(log N) 优化到摊还 O(1)?
  7. 自定义比较函数:当使用自定义对象作为 map 的 key 时,如何提供自定义的比较逻辑?如果比较逻辑不满足“严格弱序”(Strict Weak Ordering),会导致什么问题?
  8. C++17 节点操作 (extract, merge):C++17 引入的 extractmerge 方法解决了什么痛点?请举例说明如何用它们在不重新分配内存的情况下修改一个 map 中元素的 key。
  9. count() 的效率:对于 std::mapcount(key) 的效率如何?它和 find(key) != end() 相比,哪个更适合用来检查 key 是否存在?multimap 呢?
  10. 迭代器与指针稳定性map/set 的插入和删除操作是否会使指向其他元素的迭代器、指针或引用失效?为什么?
  11. map 中的 const Key:为什么从 std::map<K, V>::iterator 中解引用得到的是 std::pair<const K, V>?Key 部分为什么是 const 的?
  12. 透明比较器 (std::less<>):在 C++14 中,如何使用 std::less<> (或std::greater<> 等) 作为模板参数,以实现异构查找?
  13. equal_rangemap::equal_range 的作用是什么?它在处理 multimap 时特别有用,为什么?
  14. 内存开销:分析 std::map<K, V> 的单节点内存开销,除了 KV,还包含哪些额外信息?
  15. 查找复杂度的本质:为什么说 map 的查找是 O(log N)?这个 N 指的是什么?

六、无序关联容器 (unordered_map, unordered_set) (66-80)

  1. 底层实现std::unordered_map 通常的底层实现是什么?请描述哈希表、桶(bucket)和链表(或开放地址法)在其中的作用。
  2. 哈希与相等:要将自定义类型作为 unordered_map 的 key,需要为其提供哪两个函数?它们之间必须满足什么关系?(即,如果 a == b,则 hash(a) 必须等于 hash(b)
  3. 哈希冲突 (Collision):什么是哈希冲突?unordered_map 是如何解决冲突的?冲突对性能有什么影响?
  4. 加载因子 (Load Factor):什么是加载因子?它如何影响 unordered_map 的性能?max_load_factor 函数的作用是什么?
  5. 重哈希 (Rehashing):什么情况下会触发 unordered_map 的重哈希?重哈希是一个昂贵的操作吗?它对迭代器有什么影响?
  6. reserve 的作用unordered_map::reserve(n)vector::reserve(n) 有何不同?它预留的是元素空间还是桶空间?
  7. 最坏情况复杂度unordered_map 的平均查找复杂度是 O(1),但最坏情况是 O(N)。请描述一个能导致最坏情况发生的场景。
  8. 桶接口 (Bucket Interface)bucket_count(), bucket_size(n), bucket(key) 这些桶接口函数有什么用?它们可以用来诊断哈希函数的质量吗?
  9. 性能陷阱:使用默认的 std::hash<std::string> 时,如果输入的字符串有很多共同的前缀,可能会导致什么性能问题?如何解决?
  10. 指针稳定性:在不发生重哈希的情况下,unordered_map 的插入操作是否会使指向已有元素的指针或引用失效?删除操作呢?
  11. unordered_map vs. std::map:在性能敏感的应用中,即使不需要有序性,std::map 有时也可能比 unordered_map 更快。请解释可能的原因(例如,哈希计算开销、缓存行伪共享等)。
  12. 不可哈希的 Key:为什么像 std::vectorstd::pair 这样的类型默认不能作为 unordered_map 的 key?如何让它们可以被用作 key?
  13. C++20 contains:C++20 为关联容器增加了 contains 方法。相比 find(key) != end()count(key),它有什么优势?
  14. 哈希函数的种子:一些哈希函数实现是带“种子”的,这有什么安全上的好处?(提示:哈希洪水攻击,Hash DoS)
  15. 开放地址法 vs. 链地址法:大多数标准库实现 unordered_map 使用链地址法。如果使用开放地址法实现,会有哪些不同的性能特性和优缺点?

七、容器适配器 (stack, queue, priority_queue) (81-85)

  1. 适配器模式:为什么 stack, queue, priority_queue 被称为“容器适配器”?它们体现了设计模式中的哪个原则?
  2. 底层容器选择std::priority_queue 默认使用 std::vector,而 std::stackstd::queue 默认使用 std::deque。请解释这些默认选择的合理性。
  3. priority_queue 实现std::priority_queue 的底层是如何实现优先级的?(提示:堆 Heap)。插入(push)和弹出(pop)操作的时间复杂度是多少?
  4. 自定义 priority_queue:如何创建一个最小堆(min-heap)而不是默认的最大堆(max-heap)?如何为自定义类型提供优先级比较逻辑?
  5. 接口限制:为什么容器适配器不允许遍历其内部元素(即没有提供迭代器)?这种接口设计背后的意图是什么?

八、高级主题 (迭代器, 内存, 异常, 并发) (86-100)

  1. 迭代器类别 (Iterator Categories):解释 C++ 的五种迭代器类别(Input, Output, Forward, Bidirectional, Random Access)及其能力。请为每个类别至少举一个 STL 容器的例子。
  2. 自定义分配器 (Allocator)std::allocator 是什么?在什么情况下你需要编写并使用一个自定义的分配器?(例如,内存池、对齐内存)
  3. STL 与线程安全:STL 容器是线程安全的吗?请详细解释标准对 STL 容器线程安全性的保证(“读-读”安全,“读-写/写-写”不安全)。
  4. 并发访问的风险:同时在不同线程中对同一个 std::vector 进行 push_back 会导致什么问题?仅仅加锁 push_back 调用本身足够吗?
  5. 节点句柄 (Node Handles):再谈 C++17 的 node_type,它如何实现容器间(例如 mapmap,甚至 mapset)高效、无异常抛出的元素转移?
  6. 不完整类型 (Incomplete Types):是否可以在容器中存储不完整类型,例如在类定义中 class A { std::vector<A> children; };?为什么可以/不可以?std::vector<std::unique_ptr<A>> 呢?
  7. std::arraystd::array 和 C 风格数组、std::vector 相比,各有什么优缺点?为什么说它是“零开销抽象”?
  8. std::span (C++20)std::span 是一个容器吗?它如何与 std::vector, std::array 等容器交互,解决了什么问题?
  9. 强异常安全保证的代价:为了在 vector::push_back 中提供强异常安全保证,当元素的移动构造函数不是 noexcept 时,实现必须回退到拷贝。请解释这背后的逻辑。
  10. 短字符串优化 (SSO):虽然不是容器,但 std::string 的短字符串优化(SSO)与 vector 的动态内存管理形成了鲜明对比。请解释 SSO 的原理,并讨论如果 vector 也尝试实现类似的优化(“短向量优化”)会面临什么挑战。
  11. allocator_traitsstd::allocator_traits 是做什么用的?为什么我们应该通过它而不是直接调用分配器的方法?
  12. 过对齐数据 (Over-aligned Data):如何在一个 std::vector 中存储需要特定内存对齐(如 16-byte 或 32-byte 对齐)的数据?
  13. 移动专用类型:对于像 std::unique_ptr 这样的移动专用(move-only)类型,它们在各种 STL 容器中的使用(插入、删除、排序)是如何工作的?有什么限制?
  14. contiguous_iterator (C++20):C++20 引入了 contiguous_iterator 概念。哪些容器的迭代器满足这个概念?这个概念有什么实际用途?
  15. 未来展望:你认为 C++ 标准库的容器在未来可能会有哪些新的发展或改进?(例如,并发容器、更灵活的内存管理、平面容器 flat_map 等)
Licensed under CC BY-NC-SA 4.0
Built with Hugo
Theme Stack designed by Jimmy