<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>三大主流容器的底层内存布局与 CPU 缓存表现 on Dorkytiger 的小屋</title>
    <link>https://www.dorkytiger.top/c-plus-plus/stl-and-templates/02-container-layout/</link>
    <description>Recent content in 三大主流容器的底层内存布局与 CPU 缓存表现 on Dorkytiger 的小屋</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <atom:link href="https://www.dorkytiger.top/c-plus-plus/stl-and-templates/02-container-layout/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>`std::vector` 动态数组的内存黑幕</title>
      <link>https://www.dorkytiger.top/c-plus-plus/stl-and-templates/02-container-layout/01-std-vector/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/c-plus-plus/stl-and-templates/02-container-layout/01-std-vector/</guid>
      <description>&lt;h3 id=&#34;一物理内存绝对连续&#34;&gt;一、物理内存：绝对连续&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;vector&lt;/code&gt; 是 C++ 唯一保证&lt;strong&gt;元素在堆内存中绝对连续排列&lt;/strong&gt;的容器（与 &lt;code&gt;std::array&lt;/code&gt; 一样，但 &lt;code&gt;array&lt;/code&gt; 在栈上）。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vector&amp;lt;int&amp;gt; v = {10, 20, 30, 40};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;堆内存 (Heap):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+──────+──────+──────+──────+──────────────────+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|  10  |  20  |  30  |  40  |  预留空间         |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+──────+──────+──────+──────+──────────────────+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ^      ^      ^      ^                       ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  |      |      |      |                       |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;v[0]   v[1]   v[2]   v[3]                   v.capacity() - 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;栈上 (Stack) — vector 对象本身 (24 字节，64位):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+────────────────────────────────────────────────────+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| _M_start (ptr)  | _M_finish (ptr) | _M_end_of_storage (ptr) |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 指向堆首         | 指向堆尾(size)   | 指向容量尾(capacity)    |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+────────────────────────────────────────────────────+
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;关键结论&lt;/strong&gt;：&lt;/p&gt;</description>
    </item>
    <item>
      <title>`std::list` 双向链表与 `std::deque` 双端队列</title>
      <link>https://www.dorkytiger.top/c-plus-plus/stl-and-templates/02-container-layout/02-std-list-std-deque/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/c-plus-plus/stl-and-templates/02-container-layout/02-std-list-std-deque/</guid>
      <description>&lt;h3 id=&#34;一stdlist-的内存灾难&#34;&gt;一、&lt;code&gt;std::list&lt;/code&gt; 的内存灾难&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;list&lt;/code&gt; 的每个节点单独 &lt;code&gt;new&lt;/code&gt; 分配，分布在堆的各个角落：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;list&amp;lt;int&amp;gt; l = {1, 2, 3, 4};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;内存布局 (每个节点独立分配):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;堆地址 0x1000: [1 | next→0x2000 | prev←null]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;堆地址 0x2000: [2 | next→0x3000 | prev←0x1000]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;堆地址 0x3000: [3 | next→0x4000 | prev←0x2000]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;堆地址 0x4000: [4 | next←null  | prev←0x3000]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;栈上:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;list 对象: [_M_node 指向 0x1000 或哨兵节点]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;遍历时的缓存行为&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CPU 遍历 list:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  读 0x1000 → Cache Miss (第一次加载缓存行，顺带加载了附近 64 字节的垃圾数据)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  读 0x2000 → Cache Miss (因为 0x2000 和 0x1000 不在同一缓存行)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  读 0x3000 → Cache Miss
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  读 0x4000 → Cache Miss
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  缓存命中率: ~0% ❌
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CPU 遍历 vector:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  读 v[0] → Cache Miss (第一次，加载了 v[0]~v[15] 到缓存行)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  读 v[1] → Cache Hit ✅ (已经在缓存里了)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  读 v[2] → Cache Hit ✅
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  缓存命中率: ~99% ✅
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;性能差距实测&lt;/strong&gt;（1 亿次遍历，Release 编译）：&lt;/p&gt;</description>
    </item>
    <item>
      <title>`std::unordered_map` 哈希表与 `std::map` 红黑树</title>
      <link>https://www.dorkytiger.top/c-plus-plus/stl-and-templates/02-container-layout/03-std-unordered-map-std-map/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://www.dorkytiger.top/c-plus-plus/stl-and-templates/02-container-layout/03-std-unordered-map-std-map/</guid>
      <description>&lt;h3 id=&#34;一stdmap-红黑树的物理布局&#34;&gt;一、&lt;code&gt;std::map&lt;/code&gt; 红黑树的物理布局&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std::map&amp;lt;int, string&amp;gt; m;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;m[5] = &amp;#34;five&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;m[3] = &amp;#34;three&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;m[7] = &amp;#34;seven&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;内存中的红黑树结构:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;堆地址 0x1000: 节点 3 [left=null|right=0x2000|parent=0x3000|color=RED  |&amp;#34;three&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;堆地址 0x2000: 节点 7 [left=null|right=null |parent=0x3000|color=BLACK|&amp;#34;seven&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;堆地址 0x3000: 节点 5 [left=0x1000|right=0x2000|parent=null|color=BLACK|&amp;#34;five&amp;#34; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ↑
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        | (根节点，平衡二叉树)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;遍历时的缓存表现&lt;/strong&gt;：每次通过指针跳到下一节点，和 &lt;code&gt;list&lt;/code&gt; 一样——缓存命中率极低。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;面试高频题&lt;/strong&gt;：&amp;ldquo;为什么 &lt;code&gt;map&lt;/code&gt; 的插入是 $O(\log N)$ 但实际可能比 &lt;code&gt;unordered_map&lt;/code&gt; 的 $O(1)$ 更快？&amp;rdquo;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当 N 很小（&amp;lt; 1000）时，红黑树的 $\log N$ 大约 10 次比较，而哈希表需要&lt;strong&gt;计算哈希值（几十条指令）+ 取模 + 可能的冲突解决&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;哈希表在元素少时，负载因子低，桶空间浪费大，&lt;strong&gt;缓存命中率比红黑树还差&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&#34;二stdunordered_map-开链哈希表&#34;&gt;二、&lt;code&gt;std::unordered_map&lt;/code&gt; 开链哈希表&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;unordered_map&amp;lt;int, string&amp;gt; um;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;um.max_load_factor(1.0);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;桶数组 (Bucket Array, 连续内存):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+───────+───────+───────+───────+───────+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 桶 0  | 桶 1  | 桶 2  | 桶 3  | ...  |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+───┬───+───┬───+───┬───+───┬───+───┬───+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    │       │       │       │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ▼       ▼       ▼       ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   节点     节点     nullptr 节点
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [5]     [13]             [7]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    │       │                │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ▼       ▼                ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  nullptr  nullptr          nullptr
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  每个桶指向一个单向/双向链表的头节点
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Rehash 的代价&lt;/strong&gt;：&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
