@@ -1201,4 +1201,90 @@ int get_number(const string& s) {
12011201
12021202在给定了优秀的哈希函数的情况下,unordered_map 比 map 快得多,尤其是对大型容器而言。
12031203
1204- #todo
1204+ ### 分配器
1205+ *内存管理 + 容器 = 经典优化魔法*
1206+
1207+ 默认标准库容器用 new 和 delete 分配空间。这很好,但是某些情况会带来性能问题。
1208+
1209+ > 假定有一个重要的、长时间运行的系统,其使用事件队列(18.4节)并且使用vector作为事件存储容器,元素以shared_ptr保存。在这种情况下,事件的最后一个用户会隐式地释放该事件:
1210+
1211+ ```cpp
1212+ struct Event {
1213+ vector<int> data = vector<int>(512);
1214+ }
1215+ list<shared_ptr<Event>> q;
1216+
1217+ void producer() {
1218+ for (int n = 0; n!=LOTS; ++n) {
1219+ lock_guard lk {m}; // 互斥信号量
1220+ q.push_back(make_shared<Event>());
1221+ cv.notify_one(); // 条件变量
1222+ }
1223+ }
1224+ ```
1225+
1226+ > 从逻辑上说,这样应该工作得很好。具备清晰的逻辑,代码也健壮、可维护。不幸的是,这会导致大量的内存碎片。当16个生产者与4个消费者处理了10万个事件后,6GB以上的内存被碎片吞噬。
1227+
1228+ * 经典碎片内存,所以对于长时间运行的系统,还是不能随便 new delete啊。*
1229+
1230+ > 解决碎片问题的传统方案是使用内存池分配器重写代码。内存池分配器用来管理固定尺寸空间分配,并且一次性分配大量的对象,而不是每次申请单独分配。幸运的是,C++直接支持这个功能。内存池分配器定义在std命名空间的pmr(多态内存资源)子空间中:
1231+
1232+ ``` cpp
1233+ pmr::synchronized_pool_resource pool;
1234+
1235+ struct Event {
1236+ vector<int > data = vector<int >{512, &pool};
1237+ }
1238+
1239+ list<shared_ptr<Event >> q {&pool};
1240+
1241+ void producer() {
1242+ for (int n = 0; n!=LOTS; ++n) {
1243+ lock_guard lk {m}; // 互斥信号量
1244+ q.push_back(allocate_shared<Event,pmr::polymorphic_allocator<Event >> {&pool});
1245+ cv.notify_one(); // 条件变量
1246+ }
1247+ }
1248+ ```
1249+
1250+ *太深奥了,感觉得看多态内存相关补一下了后面。*
1251+
1252+ 多态资源必须从 memory_resource 派生,并且定义了成员函数 allocate()、deallocate() 和 is_equal().
1253+
1254+ ### 容器概述
1255+
1256+ | 容器名 | 内容 |
1257+ | ------------------------- | ----------------- |
1258+ | `vector<T>` | 可变尺寸数组 |
1259+ | `list<T>` | 双向链表 |
1260+ | `forward_list<T>` | 单向链表 |
1261+ | `deque<T>` | 双端队列 |
1262+ | `map<K,V>` | 关联数组 |
1263+ | `multimap<K,V>` | 关键字可重复的 map |
1264+ | `unordered_map<K,V>` | 哈希查找实现的 map |
1265+ | `unordered_multimap<K,V>` | 哈希版本的多值 map |
1266+ | `set<T>` | 只有关键字没有值的 map(集合) |
1267+ | `multiset<T>` | 值可以出现多次的集合 |
1268+ | `unordered_set<T>` | 哈希版本的集合 |
1269+ | `unordered_multiset<T>` | 哈希版本的多值集合 |
1270+ 标准库还提供了容器适配器比如说 `queue<T>` `stack<T>` `priority_queue<T>`. 还有定长数组 `array<T,N>` 和 `bitset<N>`.
1271+
1272+ *草了,好多细节。*
1273+
1274+ 注意一下 emplace_back 和 push_back 区别吧。
1275+
1276+ > emplace操作(比如emplace_back())获取元素构造函数的参数,并在容器中新分配的空间中直接构建对象,而不是将对象拷贝到容器中。例如,对于vector<pair<int,string>>类型,我们可以这样写:
1277+
1278+ ```cpp
1279+ v.push_back(pair{1,"copy or move"}); // 赋值或者移动构造
1280+ v.emplace_back(1, "build in place"); // 就地构造
1281+ ```
1282+
1283+ 不过上面这种简单情况,优化器会优化成同等性能。
1284+
1285+ ### 建议
1286+
1287+ - 标准库容器定义一个序列
1288+ -
1289+
1290+ #todo
0 commit comments