-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
387 lines (234 loc) · 282 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>^_^</title>
<icon>https://www.gravatar.com/avatar/9b56c310f2d1c05e0d67ae7ff77d9d75</icon>
<subtitle>在你的立足之地深挖下去,就会有泉水涌出!别管蒙昧者们叫嚷:“下面是地狱”</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="http://yoursite.com/"/>
<updated>2019-04-30T13:21:57.841Z</updated>
<id>http://yoursite.com/</id>
<author>
<name>wanyaoqi</name>
<email>wanyaoqi1995@163.com</email>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>I/O虚拟化 && SR-IOV</title>
<link href="http://yoursite.com/2018/06/17/IO%E8%99%9A%E6%8B%9F%E5%8C%96--SR-IOV/"/>
<id>http://yoursite.com/2018/06/17/IO虚拟化--SR-IOV/</id>
<published>2018-06-17T03:56:04.000Z</published>
<updated>2019-04-30T13:21:57.841Z</updated>
<content type="html"><![CDATA[<h2 id="1-介绍"><a href="#1-介绍" class="headerlink" title="1.介绍"></a>1.介绍</h2><p> 在Guest和Host间添加虚拟化层会引入很大的开销;计算工业界中一直在努力来解决这种开销。<br> 为此,英特尔推出了一系列在英特尔虚拟化技术(intel@ VT )支持下的处理器、芯片组和以太网控制器增强功能。intel@ VT 系列技术可提高虚拟化平台的性能、效率和健壮性。<br> 在此之上 PCI-SIG 制定了一种单根I/O虚拟化规范(SR-IOV) ,SR-IOV 的做法是在 I/O 子系统中开发一种扩展机制,以解决 I/O 设备的共享问题。<br><img src="/imgs/SR-IOV/imagex.png" alt="figure1"></p><a id="more"></a><h2 id="2-背景"><a href="#2-背景" class="headerlink" title="2.背景"></a>2.背景</h2><h3 id="2-1-I-O-虚拟化的目标"><a href="#2-1-I-O-虚拟化的目标" class="headerlink" title="2.1 I/O 虚拟化的目标"></a>2.1 I/O 虚拟化的目标</h3><p> I/O 虚拟化方案需要为虚机提供与在单独的物理计算机上运行时相同的隔离环境。解决方案需要提供可扩展性,以支持利用空闲资源所需的虚拟机( VMs )数量。还应为 I/O 操作提供近乎宿主机的性能。隔离应提供存储空间的隔离, 还包括需要为 I/O 分流、中断分流,以及在共享设备的情况下隔离控制操作、I/O操作和异常处理的能力。</p><h3 id="2-2-模拟-I-O"><a href="#2-2-模拟-I-O" class="headerlink" title="2.2 模拟 I/O"></a>2.2 模拟 I/O</h3><h4 id="全虚拟化:"><a href="#全虚拟化:" class="headerlink" title="全虚拟化:"></a>全虚拟化:</h4><p> 虚拟机并不知道运行在虚拟化环境中,I/O操作由hypervisor捕获,然后模拟;hypervisor捕获vm的I/O操作,然后模拟I/O操作</p><p><img src="/imgs/SR-IOV/image.png" alt="figure2"></p><ul><li>优点是可以模拟出各种各样的硬件设备;</li><li>缺点是每次 I/O 操作的路径比较长,需要多次上下文切换和VMExit,性能较差。</li></ul><h4 id="半虚拟化:"><a href="#半虚拟化:" class="headerlink" title="半虚拟化:"></a>半虚拟化:</h4><p> 虚拟机知道自己运行在虚拟化环境内,并配合hypervisor完成I/O操作</p><p><img src="/imgs/SR-IOV/image1.png" alt="figure1"></p><p> 目前 KVM 采用的的是 virtio 设备驱动框架,它提供了一种 Host 与 Guest 交互的 IO 框架。</p><p><img src="/imgs/SR-IOV/image2.png" alt="figure1"></p><p> KVM/QEMU 中 virtio 的实现采用在 Guest 内核中安装前端驱动 (Front-end driver)和在 QEMU 中实现后端驱动(Back-end)的方式。前后端驱动通过 vring 直接通信,绕过了经过 KVM 内核模块的过程,达到提高 I/O 性能的目的。</p><p> 纯软件模拟的设备和 virtio 设备的区别:virtio 省去了纯模拟模式下的异常捕获环节,Guest OS 可以和 QEMU 的 I/O 模块直接通信。</p><p><img src="/imgs/SR-IOV/image3.png" alt="figure1"></p><p> virtio-ring实现了环形缓冲区(ring buffer),用于保存前端驱动和后端处理程序执行的信息,并且它可以一次性保存前端驱动的多次I/O请求,并且交由后端去动去批量处理,最后实际调用宿主机中设备驱动实现物理上的I/O操作,这样做就可以根据约定实现批量处理而不是客户机中每次I/O请求都需要处理一次,从而提高客户机与hypervisor信息交换的效率。</p><ul><li>缺点:需要客户机中virtio相关驱动的支持(较老的系统默认没有自带这些驱动,Windows系统中需要额外安装virtio驱动),故兼容性较差,而且I/O频繁时的CPU使用率较高</li></ul><h3 id="2-3-设备直接分配"><a href="#2-3-设备直接分配" class="headerlink" title="2.3 设备直接分配"></a>2.3 设备直接分配</h3><h4 id="2-3-1-pci-passthrough"><a href="#2-3-1-pci-passthrough" class="headerlink" title="2.3.1 pci passthrough"></a>2.3.1 pci passthrough</h4><p> 随着硬件虚拟化技术的发展,Intel 和 AMD 都在处理器架构中提供对设备透传的支持(Intel 称为Virtualization Technology for Directed I/O (VT-d), AMD 称之为 I/O Memory Management Unit (IOMMU))</p><p><strong>VT-d: 提供将 PCI 物理地址映射到客户虚拟系统的方法</strong></p><ul><li><strong>DMA remapping</strong>: 支持针对虚拟机DMA访问的地址转换。 </li></ul><blockquote><p>虚拟机的操作系统(Guest OS)所提供的物理地址称为Guest Physical Address (GPA) ,它不一定与实际的物理地 址一致,也就是Host Physical Address (HPA),而DMA技术则要求访问真实的物理地址。DMA Remapping技术可以把Guest OS提供的GPA转化成HPA,然后数据就可以直接发送到Guest OS的缓冲区了。</p></blockquote><ul><li><strong>Interrupt remapping</strong>:支持虚拟机对设备中断的路由和隔离。</li></ul><blockquote><p>I/O设备会产生非常多的中断请求,I/O虚拟化必须正确地分离这些请求,并路由到不同的虚拟机上。传统设备的中断请求可以具有两种方式:一种将通过I/O中断控制器路由,一种是通过DMA写请求直接发送MSI(message signaled interrupts,消息中断),由于需要在DMA请求内嵌入目标内存地址,因此这个架构须要完全访问所有的内存地址,并不能实现中断隔离。 VT-d实现的中断重映射(interrupt-remapping)架构通过重新定义MSI的格式来解决这个问题,新的MSI仍然是一个DMA写请求的形式,不过并不嵌入目标内存地址,取而代之的是一个消息ID,通过维护一个表结构,硬件可以通过不同的消息ID辨认不同的虚拟机区域。VT-d实现的中断重映射可以支持所有的I/O源,包括IOAPICs,以及所有的中断类型,如通常的MSI以及扩展的MSI-X。</p></blockquote><ul><li><strong>MSI:</strong>另一种重要的技术是中断虚拟化MSI, MSI 将中断转换为更容易虚拟化的消息(缩放为数千个独立中断),而不是依赖将被关联到的一个物理中断引脚( pin)。MSI 是理想的 I/O 虚拟化技术,因为它支持多个中断源的隔离(而不是必须通过软件多路传输或路由的物理 pin)。</li></ul><blockquote><p>MSI的全称是Message Signaled Interrupt.MSI出现在PCI 2.2和PCIe的规范中,是一种内部中断信号机制。传统的中断都有专门的中断pin,当中断信号产生时,中断PIN电平产生变化(一般是拉低)</p><p>然而PCIe并没有多根独立的中断PIN,它使用特殊的信号来模拟中断PIN的置位和复位。MSI允许设备向一段指定的MMIO地址空间写一小段数据,然后ChipSet以此产生相应的中断给CPU. 这个特点带来的最主要的好处就是脱离了传统的interrupt pin的约束,中断的数目也不再受到限制。</p></blockquote><h4 id="2-3-2-VFIO"><a href="#2-3-2-VFIO" class="headerlink" title="2.3.2 VFIO"></a>2.3.2 VFIO</h4><p> VFIO是一个可以<strong>安全</strong>的把设备I/O、中断、DMA等暴露到用户空间(userspace),从而可以在用户空间完成设备驱动的框架。用户空间直接设备访问,虚拟机设备分配可以获得更高的IO性能。</p><p>它提供两种基本服务:</p><ul><li>向用户态提供访问硬件设备的接口</li><li>向用户态提供配置IOMMU的接口</li></ul><p>在虚拟化情景下,亦可用来在用户态实现device passthrough.</p><p> 由于device本身的特性、互连(interconnect)及IOMMU的拓扑等,IOMMU提供device 隔离(ioslation)的最小粒度是group,而不是device。如一个pci device可能包括多个function,而这些function之间数据传递可以通过专用通道(backdoor),而不经过IOMMU等等,所以device并不适合做隔离的最小单元。</p><p> VFIO据此做出container的概念,可容纳多个IOMMU group。打开/dev/vfio文件即新建一个空的container。在VFIO中,container是IOMMU操作的最小对象。</p><p>要使用VFIO,需先将设备与原驱动拨离,并与VFIO绑定。</p><p>用VFIO访问硬件的步骤:</p><blockquote><ul><li>打开设备所在IOMMU group在/dev/vfio/目录下的文件</li><li>使用VFIO_GROUP_GET_DEVICE_FD得到表示设备的文件描述 (参数为设备名称,一个典型的PCI设备名形如0000:03.00.01) </li><li>对设备进行read/write/mmap等操作</li></ul></blockquote><p> 得益于vfio低开销的用户空间直接设备访问,虚拟机设备分配(device assignment)、高性能应用等可以获得更高的I/O性能。</p><h2 id="3-SR-IOV"><a href="#3-SR-IOV" class="headerlink" title="3. SR-IOV"></a>3. SR-IOV</h2><p>SR-IOV(PCI-SIG Single Root I/O Virtualization and Sharing)是PCI-SIG组织发布的规范。</p><p><strong>SR-IOV 设计目标</strong>:通过为虚拟机提供独立的I/O地址空间、中断和DMA流而避免VMM的介入;允许设备支持多个虚拟功能,并且最小化每个附加功能的硬件成本。</p><blockquote><p>SR-IOV引入了两个PCIe的function types</p><ul><li>Physical Functions(PFs):包括管理SR-IOV功能在内的所有PCIe function。</li><li>Virtual Functions(VFs):一部分轻量级的PCIe function,只能进行必要的数据操作和配置。</li></ul></blockquote><p><img src="/imgs/SR-IOV/imagey.png" alt="figure1"></p><p>SR-IOV机制提供独立多个可配置的VF,每一个VF具有独立的PCIe配置空间。VF 是“轻量级”PCIe功能,包含数据传输所需的资源,提供了一种数据输入和输出的机制。</p><p>虚拟机中的VF驱动程序应该是半虚拟化驱动程序(知道它在虚拟化环境中),并且只执行它可用的操作。</p><blockquote><p> VF驱动程序是一个专门的驱动程序,它只有某些可用的功能,例如能够在VF中配置DMA描述符、配置MAC地址、VLAN标签等。</p><p> 通常,VF提供发送和接收数据的能力, 以及执行复位的功能,复位仅影响VF本身,而不影响整个物理设备。对于超出VF复位或发送和接收数据的动作,VF驱动程序需要与主驱动程序通信。</p></blockquote><p><img src="/imgs/SR-IOV/image9.png" alt="figure1"></p><h3 id="3-1-SR-IOV相关的虚拟化技术"><a href="#3-1-SR-IOV相关的虚拟化技术" class="headerlink" title="3.1 SR-IOV相关的虚拟化技术"></a>3.1 SR-IOV相关的虚拟化技术</h3><ul><li><h4 id="Alternative-Routing-ID-Interpretation-ARI"><a href="#Alternative-Routing-ID-Interpretation-ARI" class="headerlink" title="Alternative Routing-ID Interpretation (ARI)"></a>Alternative Routing-ID Interpretation (ARI)</h4></li></ul><p><img src="/imgs/SR-IOV/image4.png" alt="figure1"></p><p><img src="/imgs/SR-IOV/image5.png" alt="figure1"></p><p><img src="/imgs/SR-IOV/image6.png" alt="figure1"></p><p>提供一种机制允许单个PCI Express设备支持8个以上的功能</p><ul><li><h4 id="Address-Translation-Services-ATS"><a href="#Address-Translation-Services-ATS" class="headerlink" title="Address Translation Services (ATS)"></a>Address Translation Services (ATS)</h4></li></ul><p><img src="/imgs/SR-IOV/image7.png" alt="figure1"></p><p>虚拟机DMA访问的地址转换;Intel 提供VT-d来实现这一功能</p><ul><li><h4 id="Access-Control-Services-ACS"><a href="#Access-Control-Services-ACS" class="headerlink" title="Access Control Services (ACS)"></a>Access Control Services (ACS)</h4></li></ul><p><img src="/imgs/SR-IOV/image8.png" alt="figure1"></p><p>PCIe规范允许 peer-to-peer transactions;意味着某些情况下数据交换可能不经过根复合体(root complex);</p><p>在虚拟化环境下一般不希望有 peer-to-peer transactions 而不经过root complex;</p><p>ACS提供一种机制,使得peer-to-peer transactions必须通过 root complex;</p><p>如果没有ACS,PCIe一端可能意外或有意(恶意)写入对等端点上的无效/非法区域,从而可能导致问题。</p><h3 id="3-2-数据流向:"><a href="#3-2-数据流向:" class="headerlink" title="3.2 数据流向:"></a>3.2 数据流向:</h3><p><img src="/imgs/SR-IOV/image10.png" alt="figure1"></p><p>第一、二步:包到达,被送往L2 进行分类和交换 </p><p>第三步: 根据目的MAC地址进行分类,这时候,改包与 缓冲池1匹配 </p><p>第四步: 网卡发起DMA操作,将一个包传递给一个VM </p><p>第五步: DMA操作到达Intel 芯片集,在这里VT-d(由Hypervisor 配置)进行DMA操作所需的地址翻译;结果使得该包被直接送入到虚拟机的VF驱动缓冲里面 </p><p>第六步: 网卡发起了MSI-X中断,表明该接收操作已经完成。该中断由Hypervisor接收。 </p><p>第七步: Hypervisor向虚拟机注入一个虚拟中断表明传输已经结束,这时候虚拟机的VF驱动就开始处理该包。 </p><h3 id="3-3-开启SR-IOV"><a href="#3-3-开启SR-IOV" class="headerlink" title="3.3 开启SR-IOV"></a>3.3 开启SR-IOV</h3><ol><li><p>BIOS中开启VT-d, SR-IOV功能 </p></li><li><p>在grub中加上 iommu=pt intel_iommu=on</p></li><li><p>配置网卡驱动/etc/modprobe.d/ixgbe.conf: options ixgbe max_vfs=63(千兆网卡支持8个vf,万兆网卡支持63个vf)</p></li></ol><p>然后重启宿主机,lspci和ip -l可以看到;</p><p>然后需要把vfs从ixgbevf驱动上解绑,绑定到pci-stub或者vfio-pci驱动上,用于device passthough;</p><h3 id="3-4-SR-IOV的优缺点:"><a href="#3-4-SR-IOV的优缺点:" class="headerlink" title="3.4 SR-IOV的优缺点:"></a>3.4 SR-IOV的优缺点:</h3><p><strong>优点:</strong></p><p>1.降低了IO延迟和对CPU的占用,获得了接近原生的IO性能,因为虚拟机直接使用VFs,没有了VMM的陷入处理。</p><p>2.数据更加安全,因为每个VF属于一个IOMMU Group,共享IOMMU Group的设备不能分配给不同的虚拟机,而每个IOMMU Group又有独立的内存。</p><p>3.相比Device assignment, 没有了一个PCI设备只能给一个虚拟机的尴尬,SR-IOV下多个虚拟机可通过独占VFs的方式共享一个PCI设备。</p><p><strong>缺点:</strong></p><p>1.使用了VFs的虚拟机不能在热迁移。</p><h2 id="4-热迁移问题:"><a href="#4-热迁移问题:" class="headerlink" title="4. 热迁移问题:"></a>4. 热迁移问题:</h2><p> 目前SR-IOV使用是通过pci passthrough 将vf(virtual function)分配给虚机,由于pci设备的状态信息等(如设备寄存器)保存在硬件中,hypervisor失去了对虚拟硬件的控制,难以同步不同 Host 上的硬件状态</p><p>解决方案:</p><p> 1. sriov + macvtap: 使用macvtap的passthru模式,将vf直接passthru到macvtap设备,然后vm使用tap设备与外界通信;这种方式使用qemu模拟网卡,避开了保存硬件信息的问题,但是比起vf passthough的方式带来了一定的性能损耗</p><p> 2. sriov + ovs:将vf passthough到vm的同时给vm分配一个ovs网卡,在vm内部做bonding,使用active-backup模式,正常使用时vf网卡up,并且作为primary;迁移时vf网卡down,使用ovs网卡</p><h3 id="4-1-sriov-macvtap:"><a href="#4-1-sriov-macvtap:" class="headerlink" title="4.1 sriov + macvtap:"></a>4.1 sriov + macvtap:</h3><p> MACVLAN是一种网络虚拟化技术。Linux使用非常轻量的方式实现MACVLAN,因为MACVLAN不使用传统的Linux bridge做隔离和区分,而是直接与Linux的以太网接口或者子接口关联,以实现在物理网络中网络和连接的隔离。MACVLAN 会根据收到包的目的 MAC 地址判断这个包需要交给哪个虚拟网卡。</p><p><img src="/imgs/SR-IOV/macvlan.png" alt="figure1"></p><p> MACVTAP 是对 MACVLAN的改进,把 MACVLAN 与 TAP 设备的特点综合一下,使用 MACVLAN 的方式收发数据包,但是收到的包不交给 network stack 处理,而是生成一个 /dev/tapX 文件,交给这个文件。</p><p><img src="/imgs/SR-IOV/macvtap.png" alt="figure1"></p><p> Passthrough 模式下,内核的 MACVLAN 数据处理逻辑被跳过,硬件决定数据如何处理,从而释放了 Host CPU 资源。</p><p> MACVTAP Passthrough 针对 MACVTAP 网络设备,目的是饶过内核里 MACVTAP 的部分软件处理过程,转而交给硬件处理。在虚拟化条件下,数据还是会先到达模拟器 I/O 层,再转发到硬件上,这样做效率有损失,但模拟器仍然控制虚拟硬件的状态及数据的走向,可以做热迁移。</p><p><img src="/imgs/SR-IOV/passthrough.png" alt="figure1"></p><h3 id="4-2-SR-IOV-OVS"><a href="#4-2-SR-IOV-OVS" class="headerlink" title="4.2 SR-IOV + OVS:"></a>4.2 SR-IOV + OVS:</h3><p>vf 网卡和ovs网卡做bonding(mode 1)</p><p><img src="/imgs/SR-IOV/image11.png" alt="figure1"> <img src="/imgs/SR-IOV/image12.png" alt="figure1"><img src="/imgs/SR-IOV/image13.png" alt="figure1"></p><p>迁移前vf网卡active;要迁移时将ovs网卡up,并置于active状态,将vf网卡down;迁移后恢复vf网卡active,ovs网卡down</p><hr><p><a href="https://www.ibm.com/developerworks/community/blogs/5144904d-5d75-45ed-9d2b-cf1754ee936a/entry/20160605?lang=en" target="_blank" rel="noopener">https://www.ibm.com/developerworks/community/blogs/5144904d-5d75-45ed-9d2b-cf1754ee936a/entry/20160605?lang=en</a></p><p><a href="https://www.cnblogs.com/sammyliu/p/4543657.html" target="_blank" rel="noopener">https://www.cnblogs.com/sammyliu/p/4543657.html</a></p><p><a href="https://www.ibm.com/developerworks/cn/linux/l-virtio/index.html" target="_blank" rel="noopener">https://www.ibm.com/developerworks/cn/linux/l-virtio/index.html</a></p><p><a href="https://www.linux-kvm.org/images/b/b4/2012-forum-VFIO.pdf" target="_blank" rel="noopener">https://www.linux-kvm.org/images/b/b4/2012-forum-VFIO.pdf</a></p><p><a href="https://huangwei.me/wiki/tech_cloud_macvlan_macvtap.html" target="_blank" rel="noopener">https://huangwei.me/wiki/tech_cloud_macvlan_macvtap.html</a></p><p>《pci-sig-sr-iov-primer-paper》</p>]]></content>
<summary type="html">
<h2 id="1-介绍"><a href="#1-介绍" class="headerlink" title="1.介绍"></a>1.介绍</h2><p> 在Guest和Host间添加虚拟化层会引入很大的开销;计算工业界中一直在努力来解决这种开销。<br> 为此,英特尔推出了一系列在英特尔虚拟化技术(intel@ VT )支持下的处理器、芯片组和以太网控制器增强功能。intel@ VT 系列技术可提高虚拟化平台的性能、效率和健壮性。<br> 在此之上 PCI-SIG 制定了一种单根I/O虚拟化规范(SR-IOV) ,SR-IOV 的做法是在 I/O 子系统中开发一种扩展机制,以解决 I/O 设备的共享问题。<br><img src="/imgs/SR-IOV/imagex.png" alt="figure1"></p>
</summary>
<category term="虚拟化" scheme="http://yoursite.com/categories/%E8%99%9A%E6%8B%9F%E5%8C%96/"/>
<category term="I/O虚拟化" scheme="http://yoursite.com/tags/I-O%E8%99%9A%E6%8B%9F%E5%8C%96/"/>
<category term="SR-IOV" scheme="http://yoursite.com/tags/SR-IOV/"/>
</entry>
<entry>
<title>RPM 使用与 SPEC 文件</title>
<link href="http://yoursite.com/2018/04/06/rpm_spec/"/>
<id>http://yoursite.com/2018/04/06/rpm_spec/</id>
<published>2018-04-06T07:20:03.000Z</published>
<updated>2019-04-30T13:22:58.900Z</updated>
<content type="html"><![CDATA[<h2 id="1-概述"><a href="#1-概述" class="headerlink" title="1. 概述"></a>1. 概述</h2><p>RPM全称是 Red Hat Package Manager(Red Hat包管理器)。</p><p>RPM的发布基于GPL协议(GNU通用公共授權條款GNU General Public License,简称GNU <em>GPL</em>、<em>GPL</em>)。</p><p>RPM有五种基本的操作功能(不包括创建软件包):安装、卸载、升级、查询、和验证。关于rpm命令的使用我们可以用以下命令:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@serverwyq wyq]# rpm --help</span><br></pre></td></tr></table></figure><p> 通常,供Linux使用的源代码包还提供一个名为 <strong>{ 软件名称 }.spec</strong> 的文件,即spec文件。如果提供spec文件,则该源代码还可以直接编译成RPM包。 </p><a id="more"></a><h2 id="2-RPM-使用"><a href="#2-RPM-使用" class="headerlink" title="2. RPM 使用"></a>2. RPM 使用</h2><h3 id="1)安装"><a href="#1)安装" class="headerlink" title="1)安装"></a>1)安装</h3><figure class="highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rpm {-i|--install} [install-options] PACKAGE_FILE ...</span><br></pre></td></tr></table></figure><p> 通过rpm -ivh可以把rpm软件包安装到系统中,使用的较多的是-ivh参数 ,使用该选项可以解决大部分rpm软件包的安装,至于详细的参数说明可用查看rpm的man 文档。</p><h3 id="2)卸载"><a href="#2)卸载" class="headerlink" title="2)卸载"></a>2)卸载</h3><figure class="highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">rpm {-e|--erase} [--allmatches] [--nodeps] [--noscripts]</span><br><span class="line"> [--notriggers] [--test] PACKAGE_NAME ...</span><br><span class="line"> </span><br><span class="line">注:</span><br><span class="line">--nodeps Don’t do a dependency check before installing or upgrading a package.(不检查依赖)</span><br><span class="line">--force Same as using --replacepkgs, --replacefiles, and --oldpackage.(相当于同时使用了这三个参数)</span><br><span class="line"></span><br><span class="line">--replacepkgs</span><br><span class="line"> Install the packages even if some of them are already installed on this system.</span><br><span class="line">--replacefiles</span><br><span class="line"> Install the packages even if they replace files from other, already installed, packages.</span><br></pre></td></tr></table></figure><p> 如果某个软件包你再也不想使用了,那就用以上这个命令彻底的把你指定的rpm软件包清除掉把。</p><h3 id="3)升级"><a href="#3)升级" class="headerlink" title="3)升级"></a>3)升级</h3><figure class="highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rpm {-U|--upgrade} [install-options] PACKAGE_FILE ...</span><br></pre></td></tr></table></figure><p> 由于开源软件更新速度快,用户当然要使用最新版本的软件包,此时最合适的就是rpm升级功能,当然最理想的参数选项就是-Uvh。</p><h3 id="4)查询"><a href="#4)查询" class="headerlink" title="4)查询"></a>4)查询</h3><figure class="highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rpm {-q|--query} [select-options] [query-options]</span><br></pre></td></tr></table></figure><p> 查看软件包的版本、依赖关系等软件包的详细说明都要用到这个选项,常用的有:</p><p> <strong>rpm -qa</strong> 是查询机器上所有已经安装的包,加上grep可以得到你想要的包名</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[root@serverwyq wyq]# rpm -qa | grep kernel</span><br><span class="line">kernel-...</span><br><span class="line">kernel-devel-...</span><br><span class="line">kernel-headers-...</span><br></pre></td></tr></table></figure><p><strong>rpm -qi</strong> + 包名 == 查看包的详细信息</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">[root@serverwyq wyq]# rpm -qi kernel-3.10.0-123.el7.x86_64 </span><br><span class="line">Name : kernel</span><br><span class="line">Install Date: 2014年07月09日 星期三 13时57分38秒</span><br><span class="line">......</span><br><span class="line">URL : http://www.kernel.org/</span><br><span class="line">Summary : The Linux kernel</span><br></pre></td></tr></table></figure><p><strong>rpm -ql</strong> + 包名 == 查看包内文件的安装路径</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">[root@serverwyq wyq]# rpm -ql kernel-3.10.0-123.el7.x86_64 |more </span><br><span class="line">/boot/.vmlinuz-3.10.0-123.el7.x86_64.hmac</span><br><span class="line">/boot/System.map-3.10.0-123.el7.x86_64</span><br><span class="line">/boot/config-3.10.0-123.el7.x86_64</span><br><span class="line">......</span><br></pre></td></tr></table></figure><h3 id="5)校验"><a href="#5)校验" class="headerlink" title="5)校验"></a>5)校验</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rpm {-V|--verify} [select-options] [verify-options]</span><br></pre></td></tr></table></figure><p> 一般我们可用通过该命令来验证已安装软件包</p><h3 id="6)解压"><a href="#6)解压" class="headerlink" title="6)解压"></a>6)解压</h3><p> RPM包是使用cpio格式打包的,因此需要先转成cpio然后解压。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rpm2cpio some.rpm | cpio -div</span><br></pre></td></tr></table></figure><h2 id="3-spec文件"><a href="#3-spec文件" class="headerlink" title="3. spec文件"></a>3. spec文件</h2><p> 其实,制作RPM软件包并不是一件复杂的工作,其中的关键在于编写SPEC软件包描述文件。</p><p> 这个文件中包含了软件包的诸多信息,如软件包的名字、版本、类别、说明摘要、创建时要执行什么指令、安装时要执行什么操作、以及软件包所要包含的文件列表等等。</p><p> 像前面rmp -qi所看的信息都是制作rpm包时在spec文件中指定的。</p><h4 id="1)Preamle"><a href="#1)Preamle" class="headerlink" title="1)Preamle"></a>1)Preamle</h4><p> 序言包含用户请求包的信息时所显示的内容。它可以包含包的功能描述、包的软件版本、版权信息和所属的包组等。Summary 是一行关于该软件包的描述,Name 是该软件包的基名,Version 是该软件的版本号, Release 是 RPM 本身的版本号,如果修复了 spec 文件中的一个错误并发布了该软件同一版本的新 RPM,就应该增加发行版号。License 应该给出一些许可说明,Group 标识软件类型。那些试图帮助人们管理 RPM 的程序通常按照组列出 RPM。您可以在/usr/share/doc/rpm-x.x.x/GROUPS 文件看到一个 Red Hat 使用的组列表。但是您还可以使用那些组名以外的名称。Source0、Source1等等给这些源文件命名(通常为 tar.gz 文件)。%{name} 和 %{version} 是 RPM 宏,它们扩展成为头中定义的 rpm 名称和版本。</p><p> 要注意的是,<strong>不要在 Source 语句中包含任何路径</strong>。缺省情况下,RPM 会在 /usr/src/redhat/SOURCES 中(对于Redhat6 系统,则是在 /root/rpmbuild/SOURCES 目录中)寻找文件,请将您的源文件复制或链接到那里。(要使 spec 文件尽量可移植的话,应当尽量避免嵌入自己开发机器上的假想路径。其他开发人员就可以指示 RPM 在别的目录下查找源文件,而不用修改您的 spec 文件。)</p><p> 接下来的部分从 %description 行开始。您应该在这里提供该软件更多的描述,这样任何人使用 rpm -qi 查询您的软件包时都可以看到它。您可以解释这个软件包做什么,描述任何警告或附加的配置指令,等等。</p><figure class="highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">Summary: Utilities for managing accounts and shadow password files.</span><br><span class="line">Name: shadow-utils</span><br><span class="line">Version: 4.0.17</span><br><span class="line">Release: 14<span class="comment">%{?dist}</span></span><br><span class="line"> </span><br><span class="line">Source0: <span class="comment">%{name}-%{version}.tar.bz2</span></span><br><span class="line">Source1: shadow-4.0.17-login.defs</span><br><span class="line">Source2: shadow-970616.useradd</span><br><span class="line"> </span><br><span class="line">Patch0: shadow-4.0.17-redhat.patch</span><br><span class="line">Patch1: shadow-4.0.3-noinst.patch</span><br><span class="line">Patch2: shadow-4.0.11.1-vipw.patch</span><br><span class="line"> </span><br><span class="line">Packager:amoblin </span><br><span class="line">Group: Application </span><br><span class="line">URL: http://www.ossxp.com </span><br><span class="line">License: GPL</span><br><span class="line">BuildRequires: autoconf, automake, libtool, gettext-devel</span><br><span class="line">BuildRequires: libselinux-devel >= 1.25.2-1</span><br><span class="line">BuildRequires: audit-libs-devel >= 1.0.10</span><br><span class="line">Requires: libselinux >= 1.25.2-1</span><br><span class="line"> </span><br><span class="line"><span class="comment">%description</span></span><br><span class="line">This package includes the necessary programs for XXX.</span><br></pre></td></tr></table></figure><h4 id="2)Prep"><a href="#2)Prep" class="headerlink" title="2)Prep"></a>2)Prep</h4><p>Prep 部分进行实际的打包准备工作,它是使用节前缀%prep表示的。主要功能有:<br> 1. 将文件 (SOURCES/) 解压到构建目录 (BUILD/)<br> 2. 应用Patch(打补丁) (SOURCES/ => BUILD/)<br> 3. 描述 “rm -rf $RPM_BUILD_ROOT”<br> 4. 描述或编辑本部分用到的命令到 PreReq:<br> 5. 通过 “-b .XXX” 描述补丁备份</p><p>%setup</p><p>-n newdir #将压缩的软件源程序在newdir目录下解开。<br>-c #在解开源程序之前先创建目录。<br>-b num #在包含多个源程序时,将第num个源程序解压缩。<br>-T #不使用缺省的解压缩操作。</p><p>通常patch补丁都会一起放到SOURCES目录下。一般参数为<br>%patchN -p1 #应用前面定义的第N个patch,-p1是忽略patch的第一层目录</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">%setup -q #最常用</span><br><span class="line">%setup -q -n newdir #将source解压至newdir</span><br><span class="line">%setup -T -b 0 #解开第一个源程序文件</span><br><span class="line">%setup -c -n newdir #创建目录newdir,并在此目录之下解开源程序</span><br><span class="line"> </span><br><span class="line">%patch1 -p1 #应用第1个补丁</span><br></pre></td></tr></table></figure><p>eg:</p><figure class="highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">%prep</span></span><br><span class="line"><span class="comment">%setup -q</span></span><br><span class="line"><span class="comment">%patch0 -p1</span></span><br><span class="line"><span class="comment">%patch1 -p1</span></span><br><span class="line"><span class="comment">%patch2 -p1</span></span><br><span class="line"><span class="comment">%patch3 -p1</span></span><br><span class="line"> </span><br><span class="line">cp <span class="comment">%{SOURCE3} lib/nscd.c</span></span><br><span class="line">rm po/*.gmo</span><br><span class="line">rm po/stamp-po</span><br></pre></td></tr></table></figure><h4 id="3)Build"><a href="#3)Build" class="headerlink" title="3)Build"></a>3)Build</h4><p>主要用于编译源码,它是使用节前缀%build表示的。一般用于configure及make的过程。</p><p>eg:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">%build</span><br><span class="line">%configure --with-selinux --without-libpam --disable-shared --with-libaudit</span><br><span class="line">make</span><br></pre></td></tr></table></figure><h4 id="4)install"><a href="#4)install" class="headerlink" title="4)install"></a>4)install</h4><p>这一节主要用于完成实际安装软件必须执行的命令,它是使用节前缀%install表示的。这一节一般是由make install指令构成,但是有时也会包含cp、mv、install等指令。</p><p>这一节还能指定在用户安装的系统上,包安装时运行的脚本。这样的脚本称为安装(卸载)脚本。它可以指定包安装前、包安装后、包除去前、包除去后的系统必须运行的外壳程序段。在用户安装的系统上,为了验证一个包是否已经成功安装的验证脚本也可由这一节指定。</p><p>eg:</p><figure class="highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">%install</span></span><br><span class="line">rm -rf <span class="formula">$RPM_BUILD_ROOT</span></span><br><span class="line"><span class="formula">make install DESTDIR=$</span>RPM_BUILD_ROOT gnulocaledir=<span class="formula">$RPM_BUILD_ROOT/%{_datadir}/locale MKINSTALLDIRS=`pwd`/mkinstalldirs</span></span><br><span class="line"><span class="formula">install -d -m 755 $</span>RPM_BUILD_ROOT/etc/default</span><br><span class="line">install -c -m 0644 <span class="comment">%{SOURCE1} $RPM_BUILD_ROOT/etc/login.defs</span></span><br><span class="line">install -c -m 0600 <span class="comment">%{SOURCE2} $RPM_BUILD_ROOT/etc/default/useradd</span></span><br><span class="line"> </span><br><span class="line">ln -s useradd <span class="formula">$RPM_BUILD_ROOT%{_sbindir}/adduser</span></span><br><span class="line"><span class="formula">ln -s %{_mandir}/man8/useradd.8 $</span>RPM_BUILD_ROOT/<span class="comment">%{_mandir}/man8/adduser.8</span></span><br><span class="line">for subdir in <span class="formula">$RPM_BUILD_ROOT/%{_mandir}/{??,??_??,??_??.*}/man* ; do</span></span><br><span class="line"><span class="formula"> test -d $</span>subdir && test -e <span class="formula">$subdir/useradd.8 && echo ".so man8/useradd.8" > $</span>subdir/adduser.8</span><br><span class="line">done</span><br><span class="line"> </span><br><span class="line"># Remove binaries we don't use.</span><br><span class="line">rm <span class="formula">$RPM_BUILD_ROOT/%{_bindir}/chfn</span></span><br><span class="line"><span class="formula">rm $</span>RPM_BUILD_ROOT/<span class="comment">%{_bindir}/chsh</span></span><br></pre></td></tr></table></figure><h4 id="5)clean"><a href="#5)clean" class="headerlink" title="5)clean"></a>5)clean</h4><p>这一节所描述的内容表示在完成包建立的工作之后,自动执行此节下的脚本进行附加的清除工作,它是使用节前缀%clean表示的。一般而言,这一节的内容是简单地使用rm -rf $RPM_BUILD_ROOT命令,不需要指定此节的其它内容。</p><p>eg:</p><figure class="highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">%clean</span></span><br><span class="line">rm -rf <span class="formula">$RPM_BUILD_ROOT</span></span><br></pre></td></tr></table></figure><h4 id="6)files"><a href="#6)files" class="headerlink" title="6)files"></a>6)files</h4><p>这一节指定构成包的文件的列表,它是使用节前缀%files表示的。此外,它还包含一系列宏控制安装后的文件属性和配置信息。</p><p>%files 列出应该捆绑到 RPM 中的文件,并能够可选地设置许可权和其它信息。在 %files 中,您可以使用 %defattr 来定义缺省的许可权、所有者和组;%defattr(-,root,root) 会安装 root 用户拥有的所有文件,使用当 RPM 从构建系统捆绑它们时它们所具有的任何许可权。</p><p>可以用 %attr(permissions,user,group) 覆盖个别文件的所有者和许可权。可以在 %files 中用一行包括多个文件。可以通过在行中添加 %doc 或 %config 来标记文件。%doc 告诉 RPM 这是一个文档文件,因此如果用户安装软件包时使用 –excludedocs,将不安装该文件。您也可以在 %doc 下不带路径列出文件名,RPM 会在构建目录下查找这些文件并在 RPM 文件中包括它们,并把它们安装到 /usr/share/doc/%{name}-%{version}。以 %doc 的形式包括 README 和 ChangeLog 这样的文件是个好主意。</p><p>%config 告诉 RPM 这是一个配置文件。在升级时,RPM 将会试图避免用 RPM 打包的缺省配置文件覆盖用户仔细修改过的配置。</p><p>注意:如果在 %files 下列出一个目录名,RPM 会包括该目录下的所有文件。通常这不是您想要的,特别对于 /bin 这样的目录。</p><p>eg:</p><figure class="highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">%files</span></span><br><span class="line"><span class="comment">%defattr(-,root,root) #指定默认权限</span></span><br><span class="line"><span class="comment">%doc NEWS doc/HOWTO README</span></span><br><span class="line"><span class="comment">%dir /etc/default</span></span><br><span class="line"><span class="comment">%attr(0644,root,root) %config(noreplace) /etc/login.defs</span></span><br><span class="line"><span class="comment">%attr(0600,root,root) %config /etc/default/useradd</span></span><br><span class="line"><span class="comment">%{_bindir}/sg</span></span><br><span class="line"><span class="comment">%{_bindir}/chage</span></span><br><span class="line"><span class="comment">%attr(0750,root,root) %{_sbindir}/user*</span></span><br><span class="line"><span class="comment">%attr(0750,root,root) %{_sbindir}/group*</span></span><br><span class="line"><span class="comment">%{_sbindir}/grpck</span></span><br><span class="line"><span class="comment">%{_sbindir}/pwck</span></span><br><span class="line"><span class="comment">%{_sbindir}/*conv</span></span><br></pre></td></tr></table></figure><h4 id="7)changlog"><a href="#7)changlog" class="headerlink" title="7)changlog"></a>7)changlog</h4><p>主要描述软件的开发记录,它是使用节前缀%changlog表示的。对于包的维护极有好处</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">%changlog</span><br><span class="line">...</span><br></pre></td></tr></table></figure><h4 id="8)example-amp-summer"><a href="#8)example-amp-summer" class="headerlink" title="8)example & summer"></a>8)example & summer</h4><figure class="highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">Summary: hello world rpm package </span><br><span class="line">Name: hello </span><br><span class="line">Version: 0.1 </span><br><span class="line">Release: 1 </span><br><span class="line"> </span><br><span class="line">License: GPL</span><br><span class="line">Source: <span class="comment">%{name}-%{version}.tar.gz</span></span><br><span class="line">Packager: amoblin </span><br><span class="line">Group: Application </span><br><span class="line">URL: http://www.ossxp.com </span><br><span class="line"> </span><br><span class="line"><span class="comment">%description</span></span><br><span class="line"> </span><br><span class="line"><span class="comment">%prep </span></span><br><span class="line"><span class="comment">%setup -q </span></span><br><span class="line"> </span><br><span class="line"><span class="comment">%build </span></span><br><span class="line"> </span><br><span class="line"><span class="comment">%install</span></span><br><span class="line">mkdir -p <span class="formula">$RPM_BUILD_ROOT/%{_bindir}</span></span><br><span class="line"><span class="formula">gcc -o hello hello.c</span></span><br><span class="line"><span class="formula">install -c -m 755 hello $</span>RPM_BUILD_ROOT/<span class="comment">%{_bindir}</span></span><br><span class="line"> </span><br><span class="line"><span class="comment">%files </span></span><br><span class="line"><span class="comment">%{_bindir}/hello</span></span><br><span class="line"> </span><br><span class="line"><span class="comment">%clean</span></span><br><span class="line">rm -rf <span class="formula">$RPM_BUILD_ROOT</span></span><br></pre></td></tr></table></figure><figure class="highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">(1)Preamle</span><br><span class="line">Summary:</span><br><span class="line"> 用一句话概括该软件包尽量多的信息。</span><br><span class="line">Name:</span><br><span class="line"> 软件包的名字,最终RPM软件包是用该名字与版本号,释出号及体系号来命名软件包的。</span><br><span class="line">Version:</span><br><span class="line"> 软件版本号。仅当软件包比以前有较大改变时才增加版本号。</span><br><span class="line">Release:</span><br><span class="line"> 软件包释出号。一般我们对该软件包做了一些小的补丁的时候就应该把释出号加1。</span><br><span class="line">Vendor:</span><br><span class="line"> 软件开发者的名字。</span><br><span class="line">Copyright:</span><br><span class="line"> 软件包所采用的版权规则。具体有:GPL(自由软件),BSD,MIT,Public Domain(公共域), Distributable(贡献),commercial(商业),Share(共享)等,一般的开发都写GPL。</span><br><span class="line">Group: </span><br><span class="line"> 软件包所属类别,具体类别在/usr/share/doc/rpm-x.x.x/GROUPS这里可以看到</span><br><span class="line">Source:</span><br><span class="line"> 源程序软件包的名字。如 stardict-2.0.tar.gz。</span><br><span class="line"><span class="comment">%description:</span></span><br><span class="line"> 软件包详细说明,可写在多个行上。</span><br><span class="line"></span><br><span class="line">(2)<span class="comment">%prep段</span></span><br><span class="line"></span><br><span class="line">这个段是预处理段,通常用来执行一些解开源程序包的命令,为下一步的编译安装作准备。<span class="comment">%prep和下面的%build,%install段一样,除了可以执行RPM所定义的宏命令(以%开头)以外,还可以执行SHELL命令,命令可以有很多行,如我们常写的tar解包命令。</span></span><br><span class="line"></span><br><span class="line">(3)build段</span><br><span class="line"></span><br><span class="line">本段是建立段,所要执行的命令为生成软件包服务,如make 命令。</span><br><span class="line"></span><br><span class="line">(4)<span class="comment">%install段</span></span><br><span class="line"></span><br><span class="line">本段是安装段,其中的命令在安装软件包时将执行,如make install命令。</span><br><span class="line"></span><br><span class="line">(5)<span class="comment">%files段</span></span><br><span class="line"></span><br><span class="line">本段是文件段,用于定义软件包所包含的文件,分为三类--说明文档(doc),配置文件(config)及执行程序,还可定义文件存取权限,拥有者及组别。</span><br><span class="line"></span><br><span class="line">(6)<span class="comment">%changelog段</span></span><br><span class="line"></span><br><span class="line">本段是修改日志段。你可以将软件的每次修改记录到这里,保存到发布的软件包中,以便查询之用。每一个修改日志都有这样一种格式:第一行是:* 星期 月 日 年 修改人 电子信箱。其中:星期、月份均用英文形式的前3个字母,用中文会报错。接下来的行写的是修改了什么地方,可写多行。一般以减号开始,便于后续的查阅。</span><br></pre></td></tr></table></figure><h2 id="4-打包"><a href="#4-打包" class="headerlink" title="4. 打包"></a>4. 打包</h2><p> 如果想发布rpm格式的源码包或者是二进制包,就要使用rpmbuild工具。</p><p> 如果我们已经根据本地源码包的成功编译安装而写了spec文件(该文件要以.spec结束),那我们就可以建立一个打包环境,也就是目录树的建立。</p><p> 一般是在目录下建立5个目录。它门分别是BUILD、SOURCE、SPEC、SRPM、RPM。</p><p> - 其中BUILD目录用来存放打包过程中的源文件,</p><p> - SOURCE用来存放打包是要用到的源文件和patch,</p><p> - SPEC用来存放spec文件,</p><p> - SRPM、RPM分别存放打包生成的rpm格式的源文件和二进制文件。</p><p>我们可以根据需要来选用不同的参数打包文件:</p><p>1) 只生成二进制格式的rpm包</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rpmbuild -bb xxx.spec</span><br></pre></td></tr></table></figure><p> 用此命令生成软件包,执行后屏幕将显示执行信息,生成的文件会在刚才建立的RPM目录下存在。</p><p>2)只生成src格式的rpm包</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rpmbuild -bs xxx.spec</span><br></pre></td></tr></table></figure><p> 生成的文件会在刚才建立的SRPM目录下存在。</p><p>3) 只需要生成完整的源文件</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rpmbuild -bp xxx.spec</span><br></pre></td></tr></table></figure><p> 源文件存在目录BUILD下。读者朋友可能对这个命令不太明白,这个命令的作用就是把tar包解开然后把所有的补丁文件合并而生成一个完整的具最新功能的源文件。</p><p>4) 完全打包</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rpmbuild -ba xxx.spec</span><br></pre></td></tr></table></figure><p> 产生以上3个过程分别生成的包。存放在相应的目录下。</p><p> 软件包制作完成后可用rpm命令查询,看看效果。如果不满意的话可以再次修改软件包描述文件,重新运行以上命令产生新的RPM软件包。</p><h2 id="end"><a href="#end" class="headerlink" title="end"></a>end</h2><hr><p><a href="https://www.ibm.com/developerworks/cn/linux/l-rpm/" target="_blank" rel="noopener">https://www.ibm.com/developerworks/cn/linux/l-rpm/</a></p><p><a href="https://www.zhukun.net/archives/7263" target="_blank" rel="noopener">https://www.zhukun.net/archives/7263</a></p><hr><p>昔我往矣,杨柳依依;今我来思,雨雪霏霏</p>]]></content>
<summary type="html">
<h2 id="1-概述"><a href="#1-概述" class="headerlink" title="1. 概述"></a>1. 概述</h2><p>RPM全称是 Red Hat Package Manager(Red Hat包管理器)。</p>
<p>RPM的发布基于GPL协议(GNU通用公共授權條款GNU General Public License,简称GNU <em>GPL</em>、<em>GPL</em>)。</p>
<p>RPM有五种基本的操作功能(不包括创建软件包):安装、卸载、升级、查询、和验证。关于rpm命令的使用我们可以用以下命令:</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@serverwyq wyq]# rpm --help</span><br></pre></td></tr></table></figure>
<p> 通常,供Linux使用的源代码包还提供一个名为 <strong>{ 软件名称 }.spec</strong> 的文件,即spec文件。如果提供spec文件,则该源代码还可以直接编译成RPM包。 </p>
</summary>
<category term="linux" scheme="http://yoursite.com/categories/linux/"/>
<category term="linux" scheme="http://yoursite.com/tags/linux/"/>
<category term="rpm" scheme="http://yoursite.com/tags/rpm/"/>
</entry>
<entry>
<title>python装饰器</title>
<link href="http://yoursite.com/2017/11/19/python%E8%A3%85%E9%A5%B0%E5%99%A8/"/>
<id>http://yoursite.com/2017/11/19/python装饰器/</id>
<published>2017-11-19T14:46:38.000Z</published>
<updated>2019-04-30T13:22:41.483Z</updated>
<content type="html"><![CDATA[<blockquote><p>Python includes a more natural way of decorating a function by using an annotation on the function that is decorated.<br><a href="https://en.wikipedia.org/wiki/Decorator_pattern" target="_blank" rel="noopener">https://en.wikipedia.org/wiki/Decorator_pattern</a><br>译:Python提供了一种更为自然的方式来装饰一个函数,这种方法通过在被装饰的函数前加一个注释来时实现。</p></blockquote><a id="more"></a><h2 id="装饰器原理"><a href="#装饰器原理" class="headerlink" title="装饰器原理"></a>装饰器原理</h2><p>看一个简单的例子:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">test</span><span class="params">(func)</span>:</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">wrapper</span><span class="params">()</span>:</span></span><br><span class="line"> func()</span><br><span class="line"> <span class="keyword">print</span> func.__name__, <span class="string">"test wrapper"</span></span><br><span class="line"> <span class="keyword">return</span> wrapper</span><br><span class="line"></span><br><span class="line"><span class="meta">@test</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">main</span><span class="params">()</span>:</span></span><br><span class="line"> <span class="keyword">print</span> <span class="string">"start main"</span></span><br><span class="line"></span><br><span class="line">main()</span><br><span class="line"><span class="keyword">print</span> main.__name__</span><br></pre></td></tr></table></figure></p><p>得到的结果是<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">start main</span><br><span class="line">main test wrapper</span><br><span class="line">wrapper</span><br></pre></td></tr></table></figure></p><p>可以看到装饰器会改变函数的属性<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">print</span> main</span><br><span class="line"><function wrapper at <span class="number">0x7f79c2437938</span>></span><br></pre></td></tr></table></figure></p><p>此时执行main函数已经被装饰器test返回的wrapper函数给替代了,即 main() == test()()<br>再看<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">test</span><span class="params">(test_arg)</span>:</span></span><br><span class="line"> <span class="keyword">print</span> test_arg</span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">wrapper</span><span class="params">(func)</span>:</span></span><br><span class="line"> <span class="keyword">print</span> <span class="string">"inner_wrapper"</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">inner_wrapper</span><span class="params">()</span>:</span></span><br><span class="line"> func()</span><br><span class="line"> <span class="keyword">print</span> func.__name__, <span class="string">"test wrapper"</span></span><br><span class="line"> <span class="keyword">return</span> inner_wrapper</span><br><span class="line"> <span class="keyword">return</span> wrapper</span><br></pre></td></tr></table></figure></p><ul><li>这时使用装饰器test必须给参数, 如果不给的话test_arg相当与main函数的地址,</li><li>此时调用wrapper会报错(原因是参数不够)。</li><li>如果去了wrapper函数的参数则inner_wrapper不会被调用</li><li>可以看出带参数的装饰器其实包装了一层外壳,先执行最外层test函数的内容,</li><li>然后将调用的函数的地址传入里层的装饰器</li></ul><p>还有一个问题就是之前代码中的func.<strong>name</strong>和main.<strong>name</strong>的问题,<br>不难看出其实main函数的地址就是wrapper的地址,所以main.<strong>name</strong>打印的是wrapper函数的名字,<br>那么如何获得main函数真正的属性呢?</p><h2 id="functools-wraps"><a href="#functools-wraps" class="headerlink" title="functools.wraps"></a>functools.wraps</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">test</span><span class="params">(func)</span>:</span></span><br><span class="line"><span class="meta"> @functools.wraps(func)</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">wrapper</span><span class="params">()</span>:</span></span><br><span class="line"> func()</span><br><span class="line"> <span class="keyword">print</span> func.__name__, <span class="string">"test wrapper"</span></span><br><span class="line"> <span class="keyword">return</span> wrapper</span><br></pre></td></tr></table></figure><p>加上functools.wraps装饰器后的打印结果如下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">start main</span><br><span class="line">main test wrapper</span><br><span class="line">main</span><br></pre></td></tr></table></figure></p><p>进入functools中看warps函数的实现其实可以看到<br>functools.wraps函数将wrapper函数的属性使用setattr设置为传入的func即main函数的属性</p>]]></content>
<summary type="html">
<blockquote>
<p>Python includes a more natural way of decorating a function by using an annotation on the function that is decorated.<br><a href="https://en.wikipedia.org/wiki/Decorator_pattern" target="_blank" rel="noopener">https://en.wikipedia.org/wiki/Decorator_pattern</a><br>译:Python提供了一种更为自然的方式来装饰一个函数,这种方法通过在被装饰的函数前加一个注释来时实现。</p>
</blockquote>
</summary>
<category term="python" scheme="http://yoursite.com/categories/python/"/>
<category term="python" scheme="http://yoursite.com/tags/python/"/>
<category term="装饰器" scheme="http://yoursite.com/tags/%E8%A3%85%E9%A5%B0%E5%99%A8/"/>
</entry>
<entry>
<title>STL deque——part 2</title>
<link href="http://yoursite.com/2016/08/20/stl_deque_2/"/>
<id>http://yoursite.com/2016/08/20/stl_deque_2/</id>
<published>2016-08-20T02:52:35.000Z</published>
<updated>2019-04-30T13:25:20.001Z</updated>
<content type="html"><![CDATA[<blockquote><p>接下来介绍一下deque的插入删除操作及其他操作(push, pop …)<br>常见的有push_back, push_front, pop_back, pop_front, insert, erase, clear等<br>包括了内存分配和释放等问题</p></blockquote><a id="more"></a><h2 id="push-pop"><a href="#push-pop" class="headerlink" title="push pop"></a>push pop</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br></pre></td><td class="code"><pre><span class="line"> <span class="comment">//在deque末尾添加元素 </span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">push_back</span><span class="params">(<span class="keyword">const</span> value_type& t)</span> </span>{ </span><br><span class="line"> <span class="keyword">if</span> (finish.cur != finish.last - <span class="number">1</span>) { </span><br><span class="line"> <span class="comment">// 当前缓冲区还有空间 </span></span><br><span class="line"> construct(finish.cur, t); <span class="comment">// 直接在可用空间构建 </span></span><br><span class="line"> ++finish.cur; <span class="comment">// 调整finish迭代器 </span></span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span> <span class="comment">// 当前缓冲区无可用空间(last不能存储元素用) </span></span><br><span class="line"> push_back_aux(t); </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> <span class="comment">//在deque头添加元素 </span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">push_front</span><span class="params">(<span class="keyword">const</span> value_type& t)</span> </span>{ </span><br><span class="line"> <span class="keyword">if</span> (start.cur != start.first) { <span class="comment">// 当前缓冲区还有空间 </span></span><br><span class="line"> construct(start.cur - <span class="number">1</span>, t); </span><br><span class="line"> --start.cur; </span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span> <span class="comment">// 当前缓冲区无空间可用了 </span></span><br><span class="line"> push_front_aux(t); </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> <span class="comment">//删掉末尾元素 </span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">pop_back</span><span class="params">()</span> </span>{ </span><br><span class="line"> <span class="keyword">if</span> (finish.cur != finish.first) {<span class="comment">//最后一个缓冲区(finish指的缓冲区)有多于一个元素(含一个) </span></span><br><span class="line"> --finish.cur; </span><br><span class="line"> destroy(finish.cur); </span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> <span class="comment">// 最后一个缓冲区无元素 </span></span><br><span class="line"> pop_back_aux(); <span class="comment">// 这里会进行缓冲区的释放工作 </span></span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> <span class="comment">//在deque头删除元素 </span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">pop_front</span><span class="params">()</span> </span>{ </span><br><span class="line"> <span class="keyword">if</span> (start.cur != start.last - <span class="number">1</span>) { </span><br><span class="line"> <span class="comment">// start.node所指缓冲区有多余一个元素(不含一个) </span></span><br><span class="line"> destroy(start.cur); </span><br><span class="line"> ++start.cur; </span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> <span class="comment">// start.node所指缓冲区只有一个元素 </span></span><br><span class="line"> pop_front_aux(); <span class="comment">// 这里会进行缓冲区释放工作 </span></span><br><span class="line"> } </span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span> <<span class="class"><span class="keyword">class</span> <span class="title">T</span>, <span class="title">class</span> <span class="title">Alloc</span>, <span class="title">size_t</span> <span class="title">BufSize</span>> </span></span><br><span class="line"><span class="class"><span class="title">void</span> <span class="title">deque</span><T, Alloc, BufSize>:</span>:push_back_aux(<span class="keyword">const</span> value_type& t) { </span><br><span class="line"> value_type t_copy = t; </span><br><span class="line"> reserve_map_at_back(); <span class="comment">// 若符合某重条件则必须重换一个map </span></span><br><span class="line"> *(finish.node + <span class="number">1</span>) = allocate_node(); <span class="comment">// 配置一个新结点(缓冲区) </span></span><br><span class="line"> __STL_TRY { </span><br><span class="line"> construct(finish.cur, t_copy); <span class="comment">// 设置值 </span></span><br><span class="line"> finish.set_node(finish.node + <span class="number">1</span>); <span class="comment">// 改变finish,令其指向新结点 </span></span><br><span class="line"> finish.cur = finish.first; <span class="comment">// 设置 finish 的状态 </span></span><br><span class="line"> } </span><br><span class="line"> __STL_UNWIND(deallocate_node(*(finish.node + <span class="number">1</span>))); </span><br><span class="line">} </span><br><span class="line"> </span><br><span class="line"><span class="comment">// 只有当start.cur == start.first才会调用。 </span></span><br><span class="line"><span class="comment">// 第一个缓冲区没有未用空间时才会调用。和上面实现类似 </span></span><br><span class="line"><span class="keyword">template</span> <<span class="class"><span class="keyword">class</span> <span class="title">T</span>, <span class="title">class</span> <span class="title">Alloc</span>, <span class="title">size_t</span> <span class="title">BufSize</span>> </span></span><br><span class="line"><span class="class"><span class="title">void</span> <span class="title">deque</span><T, Alloc, BufSize>:</span>:push_front_aux(<span class="keyword">const</span> value_type& t) { </span><br><span class="line"> value_type t_copy = t; </span><br><span class="line"> reserve_map_at_front(); </span><br><span class="line"> *(start.node - <span class="number">1</span>) = allocate_node(); </span><br><span class="line"> __STL_TRY { </span><br><span class="line"> start.set_node(start.node - <span class="number">1</span>); </span><br><span class="line"> start.cur = start.last - <span class="number">1</span>; </span><br><span class="line"> construct(start.cur, t_copy); </span><br><span class="line"> }</span><br><span class="line">} </span><br><span class="line"><span class="comment">// 只有当finish.cur == finish.first才会调用 </span></span><br><span class="line"><span class="keyword">template</span> <<span class="class"><span class="keyword">class</span> <span class="title">T</span>, <span class="title">class</span> <span class="title">Alloc</span>, <span class="title">size_t</span> <span class="title">BufSize</span>> </span></span><br><span class="line"><span class="class"><span class="title">void</span> <span class="title">deque</span><T, Alloc, BufSize>:</span>:pop_back_aux() { </span><br><span class="line"> deallocate_node(finish.first); </span><br><span class="line"> finish.set_node(finish.node - <span class="number">1</span>); </span><br><span class="line"> finish.cur = finish.last - <span class="number">1</span>; </span><br><span class="line"> destroy(finish.cur); </span><br><span class="line">} </span><br><span class="line"><span class="comment">// 只有当start.cur == start.last - 1时才会调用 </span></span><br><span class="line"><span class="keyword">template</span> <<span class="class"><span class="keyword">class</span> <span class="title">T</span>, <span class="title">class</span> <span class="title">Alloc</span>, <span class="title">size_t</span> <span class="title">BufSize</span>> </span></span><br><span class="line"><span class="class"><span class="title">void</span> <span class="title">deque</span><T, Alloc, BufSize>:</span>:pop_front_aux() { </span><br><span class="line"> destroy(start.cur); </span><br><span class="line"> deallocate_node(start.first); </span><br><span class="line"> start.set_node(start.node + <span class="number">1</span>); </span><br><span class="line"> start.cur = start.first; </span><br><span class="line">} </span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">//在map尾添加缓冲区 </span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">reserve_map_at_back</span> <span class="params">(size_type nodes_to_add = <span class="number">1</span>)</span> </span>{ </span><br><span class="line"> <span class="keyword">if</span> (nodes_to_add + <span class="number">1</span> > map_size - (finish.node - <span class="built_in">map</span>)) </span><br><span class="line"> <span class="comment">//map空间不够用,则开辟新的map空间,把原来map内容拷贝过来。释放原来的 </span></span><br><span class="line"> reallocate_map(nodes_to_add, <span class="literal">false</span>); </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> <span class="comment">//在map头添加缓冲区 </span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">reserve_map_at_front</span> <span class="params">(size_type nodes_to_add = <span class="number">1</span>)</span> </span>{ </span><br><span class="line"> <span class="keyword">if</span> (nodes_to_add > start.node - <span class="built_in">map</span>) </span><br><span class="line"> reallocate_map(nodes_to_add, <span class="literal">true</span>); </span><br><span class="line"> } </span><br><span class="line"></span><br><span class="line"><span class="comment">//添加map结点,指向新的缓冲区,add_at_front=true添加在map头,否则添加在尾 </span></span><br><span class="line"><span class="keyword">template</span> <<span class="class"><span class="keyword">class</span> <span class="title">T</span>, <span class="title">class</span> <span class="title">Alloc</span>, <span class="title">size_t</span> <span class="title">BufSize</span>> </span></span><br><span class="line"><span class="class"><span class="title">void</span> <span class="title">deque</span><T, Alloc, BufSize>:</span>:reallocate_map(size_type nodes_to_add, </span><br><span class="line"> <span class="keyword">bool</span> add_at_front) { </span><br><span class="line"> size_type old_num_nodes = finish.node - start.node + <span class="number">1</span>; </span><br><span class="line"> size_type new_num_nodes = old_num_nodes + nodes_to_add; </span><br><span class="line"> </span><br><span class="line"> map_pointer new_nstart; </span><br><span class="line"> <span class="keyword">if</span> (map_size > <span class="number">2</span> * new_num_nodes) { </span><br><span class="line"> new_nstart = <span class="built_in">map</span> + (map_size - new_num_nodes) / <span class="number">2</span> </span><br><span class="line"> + (add_at_front ? nodes_to_add : <span class="number">0</span>); </span><br><span class="line"> <span class="keyword">if</span> (new_nstart < start.node) </span><br><span class="line"> copy(start.node, finish.node + <span class="number">1</span>, new_nstart); </span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> copy_backward(start.node, finish.node + <span class="number">1</span>, new_nstart + old_num_nodes); </span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span> { </span><br><span class="line"> size_type new_map_size = map_size + max(map_size, nodes_to_add) + <span class="number">2</span>; </span><br><span class="line"> <span class="comment">// 配置新的结点,准备给map使用 </span></span><br><span class="line"> map_pointer new_map = map_allocator::allocate(new_map_size); </span><br><span class="line"> new_nstart = new_map + (new_map_size - new_num_nodes) / <span class="number">2</span> </span><br><span class="line"> + (add_at_front ? nodes_to_add : <span class="number">0</span>); </span><br><span class="line"> <span class="comment">// 把原map 內容拷贝 </span></span><br><span class="line"> copy(start.node, finish.node + <span class="number">1</span>, new_nstart); </span><br><span class="line"> <span class="comment">// 释放放原map </span></span><br><span class="line"> map_allocator::deallocate(<span class="built_in">map</span>, map_size); </span><br><span class="line"> <span class="comment">// 设置新map起始位置和大小 </span></span><br><span class="line"> <span class="built_in">map</span> = new_map; </span><br><span class="line"> map_size = new_map_size; </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 重新设置迭代器 start 和 finish </span></span><br><span class="line"> start.set_node(new_nstart); </span><br><span class="line"> finish.set_node(new_nstart + old_num_nodes - <span class="number">1</span>); </span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="insert"><a href="#insert" class="headerlink" title="insert"></a>insert</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"> <span class="comment">// 在position 处插入一個元素,其值为 x </span></span><br><span class="line"> <span class="function">iterator <span class="title">insert</span><span class="params">(iterator position, <span class="keyword">const</span> value_type& x)</span> </span>{ </span><br><span class="line"> <span class="keyword">if</span> (position.cur == start.cur) { <span class="comment">// position是deque的最前端,则调用push_front()</span></span><br><span class="line"> push_front(x); </span><br><span class="line"> <span class="keyword">return</span> start; </span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (position.cur == finish.cur) { <span class="comment">// position是deque的最末端,则调用push_back()</span></span><br><span class="line"> push_back(x); </span><br><span class="line"> iterator tmp = finish; </span><br><span class="line"> --tmp; </span><br><span class="line"> <span class="keyword">return</span> tmp; </span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span> { </span><br><span class="line"> <span class="keyword">return</span> insert_aux(position, x); <span class="comment">// 都不是就交给insert_aux 去做 </span></span><br><span class="line"> } </span><br><span class="line"> } </span><br><span class="line"><span class="comment">//在pos处插入一个元素,值为x。要判断插入点距头更近还是尾更近</span></span><br><span class="line"><span class="keyword">template</span> <<span class="class"><span class="keyword">class</span> <span class="title">T</span>, <span class="title">class</span> <span class="title">Alloc</span>, <span class="title">size_t</span> <span class="title">BufSize</span>> </span></span><br><span class="line"><span class="class"><span class="title">typename</span> <span class="title">deque</span><T, Alloc, BufSize>:</span>:iterator </span><br><span class="line"><span class="built_in">deque</span><T, Alloc, BufSize>::insert_aux(iterator pos, <span class="keyword">const</span> value_type& x) { </span><br><span class="line"> difference_type index = pos - start; </span><br><span class="line"> value_type x_copy = x; </span><br><span class="line"> <span class="keyword">if</span> (index < size() / <span class="number">2</span>) { <span class="comment">//插入点之前的元素少</span></span><br><span class="line"> push_front(front()); </span><br><span class="line"> iterator front1 = start; </span><br><span class="line"> ++front1; </span><br><span class="line"> iterator front2 = front1; </span><br><span class="line"> ++front2; </span><br><span class="line"> pos = start + index; </span><br><span class="line"> iterator pos1 = pos; </span><br><span class="line"> ++pos1; </span><br><span class="line"> copy(front2, pos1, front1); </span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span> { <span class="comment">//插入点之后的元素少</span></span><br><span class="line"> push_back(back()); </span><br><span class="line"> iterator back1 = finish; </span><br><span class="line"> --back1; </span><br><span class="line"> iterator back2 = back1; </span><br><span class="line"> --back2; </span><br><span class="line"> pos = start + index; </span><br><span class="line"> copy_backward(pos, back2, back1); </span><br><span class="line"> } </span><br><span class="line"> *pos = x_copy; </span><br><span class="line"> <span class="keyword">return</span> pos; </span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="resize"><a href="#resize" class="headerlink" title="resize"></a>resize</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//调整deque的大小。</span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">resize</span><span class="params">(size_type new_size, <span class="keyword">const</span> value_type& x)</span> </span>{ </span><br><span class="line"> <span class="keyword">const</span> size_type len = size(); </span><br><span class="line"> <span class="keyword">if</span> (new_size < len) <span class="comment">//如果deque变小,直接擦除掉多余的元素</span></span><br><span class="line"> erase(start + new_size, finish); </span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> insert(finish, new_size - len, x); <span class="comment">//如果deque变大,则在deque后面插入元素补充</span></span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">resize</span><span class="params">(size_type new_size)</span> </span>{ resize(new_size, value_type()); }</span><br></pre></td></tr></table></figure><h2 id="erase"><a href="#erase" class="headerlink" title="erase"></a>erase</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"> <span class="comment">// 清除 pos 所指的元素。 </span></span><br><span class="line"> <span class="comment">//判断pos距离头近还是距离尾近,距离那个位置近就移动那个位置的元素,保证移动元素个数最少 </span></span><br><span class="line"> <span class="function">iterator <span class="title">erase</span><span class="params">(iterator pos)</span> </span>{ </span><br><span class="line"> iterator next = pos; </span><br><span class="line"> ++next; </span><br><span class="line"> difference_type index = pos - start; <span class="comment">// pos和deque开头元素的个数 </span></span><br><span class="line"> <span class="keyword">if</span> (index < (size() >> <span class="number">1</span>)) { <span class="comment">// size() >> 1为size()/2 </span></span><br><span class="line"> <span class="comment">//如果pos距离deque头比较近的话,deque的开头到pos元素向后移 </span></span><br><span class="line"> copy_backward(start, pos, next); </span><br><span class="line"> pop_front(); <span class="comment">// 移动后,删除第一个元素 </span></span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span> { <span class="comment">// 否则pos+1到结尾元素向前移, </span></span><br><span class="line"> copy(next, finish, pos); </span><br><span class="line"> pop_back(); </span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">return</span> start + index; </span><br><span class="line"> } </span><br><span class="line"></span><br><span class="line"><span class="comment">//擦除两个迭代器之间的元素 </span></span><br><span class="line"><span class="keyword">template</span> <<span class="class"><span class="keyword">class</span> <span class="title">T</span>, <span class="title">class</span> <span class="title">Alloc</span>, <span class="title">size_t</span> <span class="title">BufSize</span>> </span></span><br><span class="line"><span class="class"><span class="title">deque</span><T, Alloc, BufSize>:</span>:iterator </span><br><span class="line"><span class="built_in">deque</span><T, Alloc, BufSize>::erase(iterator first, iterator last) { </span><br><span class="line"> <span class="keyword">if</span> (first == start && last == finish) { <span class="comment">// 如果是清除整个 deque </span></span><br><span class="line"> clear(); <span class="comment">// 直接调用 clear() 即可 </span></span><br><span class="line"> <span class="keyword">return</span> finish; </span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span> { </span><br><span class="line"> difference_type n = last - first; <span class="comment">// 擦除区间长度 </span></span><br><span class="line"> difference_type elems_before = first - start; <span class="comment">// 擦除区间前方元素的个数 </span></span><br><span class="line"> <span class="keyword">if</span> (elems_before < (size() - n) / <span class="number">2</span>) { <span class="comment">// 如果前方的元素少, </span></span><br><span class="line"> copy_backward(start, first, last); <span class="comment">// 前方元素向后移(覆盖擦除区间) </span></span><br><span class="line"> iterator new_start = start + n; <span class="comment">// deque 的新起点 </span></span><br><span class="line"> destroy(start, new_start); <span class="comment">// 多于元素析构 </span></span><br><span class="line"> <span class="comment">// 释放多于元素所占内存 </span></span><br><span class="line"> <span class="keyword">for</span> (map_pointer cur = start.node; cur < new_start.node; ++cur) </span><br><span class="line"> data_allocator::deallocate(*cur, buffer_size()); </span><br><span class="line"> start = new_start; </span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span> { <span class="comment">// 后方元素更少 </span></span><br><span class="line"> copy(last, finish, first); <span class="comment">//后方元素向前移动(覆盖擦除区间) </span></span><br><span class="line"> iterator new_finish = finish - n; </span><br><span class="line"> destroy(new_finish, finish); </span><br><span class="line"> <span class="comment">// 释放多于元素所占内存</span></span><br><span class="line"> <span class="keyword">for</span> (map_pointer cur = new_finish.node + <span class="number">1</span>; cur <= finish.node; ++cur) </span><br><span class="line"> data_allocator::deallocate(*cur, buffer_size()); </span><br><span class="line"> finish = new_finish; </span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">return</span> start + elems_before; </span><br><span class="line"> } </span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="clear"><a href="#clear" class="headerlink" title="clear"></a>clear</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//清空deque。最后保留了一个缓冲区,这是deque的策略,也是其初始状态 </span></span><br><span class="line"><span class="keyword">template</span> <<span class="class"><span class="keyword">class</span> <span class="title">T</span>, <span class="title">class</span> <span class="title">Alloc</span>, <span class="title">size_t</span> <span class="title">BufSize</span>> </span></span><br><span class="line"><span class="class"><span class="title">void</span> <span class="title">deque</span><T, Alloc, BufSize>:</span>:clear() { </span><br><span class="line"> <span class="comment">//头尾以外的缓冲区,它们肯定是满的。 </span></span><br><span class="line"> <span class="keyword">for</span> (map_pointer node = start.node + <span class="number">1</span>; node < finish.node; ++node) { </span><br><span class="line"></span><br><span class="line"> destroy(*node, *node + buffer_size()); </span><br><span class="line"> data_allocator::deallocate(*node, buffer_size()); </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> (start.node != finish.node) { <span class="comment">// 至少有2个以上(含)缓冲区 </span></span><br><span class="line"> destroy(start.cur, start.last); <span class="comment">// 头缓冲区元素析构 </span></span><br><span class="line"> destroy(finish.first, finish.cur); <span class="comment">// 尾缓冲区元素析构 </span></span><br><span class="line"> <span class="comment">// 释放尾缓冲区,保留了头缓冲区 </span></span><br><span class="line"> data_allocator::deallocate(finish.first, buffer_size()); </span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span> <span class="comment">// 只有一个缓冲区 </span></span><br><span class="line"> destroy(start.cur, finish.cur); <span class="comment">// 析构,但是不释放 </span></span><br><span class="line"> </span><br><span class="line"> finish = start; <span class="comment">// 调整迭代器,deque为空 </span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<blockquote>
<p>接下来介绍一下deque的插入删除操作及其他操作(push, pop …)<br>常见的有push_back, push_front, pop_back, pop_front, insert, erase, clear等<br>包括了内存分配和释放等问题</p>
</blockquote>
</summary>
<category term="Summary" scheme="http://yoursite.com/categories/Summary/"/>
<category term="C++" scheme="http://yoursite.com/tags/C/"/>
<category term="STL" scheme="http://yoursite.com/tags/STL/"/>
<category term="list" scheme="http://yoursite.com/tags/list/"/>
</entry>
<entry>
<title>STL deque——part 1</title>
<link href="http://yoursite.com/2016/08/18/stl_deque_1/"/>
<id>http://yoursite.com/2016/08/18/stl_deque_1/</id>
<published>2016-08-18T13:59:56.000Z</published>
<updated>2019-04-30T13:25:11.134Z</updated>
<content type="html"><![CDATA[<h1 id="deque概述"><a href="#deque概述" class="headerlink" title="deque概述"></a>deque概述</h1><p>deque是一个双端队列</p><a id="more"></a><p><img src="/imgs/stl_deque/deque_1.png" alt="1"><br><img src="/imgs/stl_deque/deque_2.png" alt="2"><br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> <<span class="class"><span class="keyword">class</span> <span class="title">T</span>, <span class="title">class</span> <span class="title">Alloc</span> = <span class="title">alloc</span>, <span class="title">size_t</span> <span class="title">BufSiz</span> = 0> </span></span><br><span class="line"><span class="class"><span class="title">class</span> <span class="title">deque</span> {</span> </span><br><span class="line"><span class="keyword">public</span>: <span class="comment">// Basic types </span></span><br><span class="line"> <span class="keyword">typedef</span> T value_type; </span><br><span class="line"> <span class="keyword">typedef</span> value_type* pointer; </span><br><span class="line"> ···</span><br><span class="line"><span class="keyword">protected</span>: <span class="comment">// Data members </span></span><br><span class="line"> iterator start; <span class="comment">// start.cur指向deque的第一个结点 </span></span><br><span class="line"> iterator finish; <span class="comment">// finish.cur指向迭代器deque的最后一个结点的后一个元素 </span></span><br><span class="line"> </span><br><span class="line"> map_pointer <span class="built_in">map</span>; <span class="comment">// 指向中控器。其实是指向中控器的第一个结点。 </span></span><br><span class="line"> <span class="comment">// 中控器是连续的,map_size定义了中控器的大小。 </span></span><br><span class="line"> </span><br><span class="line"> size_type map_size; <span class="comment">// 中控器的大小。</span></span><br><span class="line"> ...</span><br><span class="line">};</span><br></pre></td></tr></table></figure></p><p><img src="/imgs/stl_deque/deque_3.png" alt="3"></p><h1 id="deque-迭代器"><a href="#deque-迭代器" class="headerlink" title="deque 迭代器"></a>deque 迭代器</h1><p><img src="/imgs/stl_deque/deque_4.png" alt="4"><br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* </span></span><br><span class="line"><span class="comment">此函数用来计算缓冲区的大小 </span></span><br><span class="line"><span class="comment">如果n不等于0,那么返回n,开发者自己决定 </span></span><br><span class="line"><span class="comment"> 否则:如果sz小于512,返回512/sz </span></span><br><span class="line"><span class="comment"> 如果sz大于512,返回1 </span></span><br><span class="line"><span class="comment">*/</span> </span><br><span class="line"><span class="keyword">inline</span> <span class="keyword">size_t</span> __deque_buf_size(<span class="keyword">size_t</span> n, <span class="keyword">size_t</span> sz) </span><br><span class="line">{ </span><br><span class="line"> <span class="keyword">return</span> n != <span class="number">0</span> ? n : (sz < <span class="number">512</span> ? <span class="keyword">size_t</span>(<span class="number">512</span> / sz) : <span class="keyword">size_t</span>(<span class="number">1</span>)); </span><br><span class="line">} </span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="comment">//deque的迭代器,未继承std::iterator </span></span><br><span class="line"><span class="keyword">template</span> <<span class="class"><span class="keyword">class</span> <span class="title">T</span>, <span class="title">class</span> <span class="title">Ref</span>, <span class="title">class</span> <span class="title">Ptr</span>, <span class="title">size_t</span> <span class="title">BufSiz</span>> </span></span><br><span class="line"><span class="class"><span class="title">struct</span> __<span class="title">deque_iterator</span> {</span> </span><br><span class="line"> <span class="keyword">typedef</span> __deque_iterator<T, T&, T*, BufSiz> iterator; </span><br><span class="line"> <span class="keyword">typedef</span> __deque_iterator<T, <span class="keyword">const</span> T&, <span class="keyword">const</span> T*, BufSiz> const_iterator; </span><br><span class="line"> <span class="function"><span class="keyword">static</span> size_t <span class="title">buffer_size</span><span class="params">()</span> </span>{<span class="keyword">return</span> __deque_buf_size(BufSiz, <span class="keyword">sizeof</span>(T)); } </span><br><span class="line"> </span><br><span class="line"> <span class="comment">//没有继承std::iterator,自己定义5个迭代器相应型别。 </span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">typedef</span> random_access_iterator_tag iterator_category; <span class="comment">// (1) </span></span><br><span class="line"> <span class="keyword">typedef</span> T value_type; <span class="comment">// (2) </span></span><br><span class="line"> <span class="keyword">typedef</span> Ptr pointer; <span class="comment">// (3) </span></span><br><span class="line"> <span class="keyword">typedef</span> Ref reference; <span class="comment">// (4) </span></span><br><span class="line"> <span class="keyword">typedef</span> <span class="keyword">size_t</span> size_type; </span><br><span class="line"> <span class="keyword">typedef</span> <span class="keyword">ptrdiff_t</span> difference_type; <span class="comment">// (5) </span></span><br><span class="line"> <span class="keyword">typedef</span> T** map_pointer; <span class="comment">//注意,是指针的指针 </span></span><br><span class="line"> <span class="comment">//map_pointer指向中控器,中控器的存储的是指针,指向node-buf结点缓冲区 </span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">typedef</span> __deque_iterator self; </span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"> T* cur; <span class="comment">// 迭代器所指元素 </span></span><br><span class="line"> T* first; <span class="comment">// 迭代器所指元素所在缓冲区的开头 </span></span><br><span class="line"> T* last; <span class="comment">// 迭代器所指元素所在缓冲区的结尾(结尾包含在缓冲区内) </span></span><br><span class="line"> map_pointer node;<span class="comment">//指向中控器的结点,这个结点指向迭代器所指元素所在的缓冲区 </span></span><br><span class="line"> </span><br><span class="line"><span class="comment">//迭代器的构造函数 </span></span><br><span class="line"> </span><br><span class="line"> <span class="comment">//x是迭代器所指结点,y为中控器中的结点的值,指向x所指缓冲区 </span></span><br><span class="line"> __deque_iterator(T* x, map_pointer y) </span><br><span class="line"> : cur(x), first(*y), last(*y + buffer_size()), node(y) {} </span><br><span class="line"> <span class="comment">//默认构造函数 </span></span><br><span class="line"> __deque_iterator() : cur(<span class="number">0</span>), first(<span class="number">0</span>), last(<span class="number">0</span>), node(<span class="number">0</span>) {} </span><br><span class="line"> <span class="comment">//用一个迭代器x初始化本迭代器 </span></span><br><span class="line"> __deque_iterator(<span class="keyword">const</span> iterator& x) </span><br><span class="line"> : cur(x.cur), first(x.first), last(x.last), node(x.node) {} </span><br><span class="line"> </span><br><span class="line"> <span class="comment">//迭代器需要重载的运算符 </span></span><br><span class="line"> reference <span class="keyword">operator</span>*() <span class="keyword">const</span> { <span class="keyword">return</span> *cur; } </span><br><span class="line"><span class="comment">/* </span></span><br><span class="line"><span class="comment">两个迭代器之间的距离。这两个迭代器可能不在同一个buffer上。 </span></span><br><span class="line"><span class="comment">*/</span> </span><br><span class="line"> difference_type <span class="keyword">operator</span>-(<span class="keyword">const</span> self& x) <span class="keyword">const</span> { </span><br><span class="line"> <span class="keyword">return</span> difference_type(buffer_size()) * (node - x.node - <span class="number">1</span>) + </span><br><span class="line"> (cur - first) + (x.last - x.cur); </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> <span class="comment">/* </span></span><br><span class="line"><span class="comment"> 迭代器前进一步。 </span></span><br><span class="line"><span class="comment"> 先++cur,再判断cur==last。说明cur不会指向last的。last所指空间不存内容 </span></span><br><span class="line"><span class="comment"> */</span> </span><br><span class="line"> self& <span class="keyword">operator</span>++() { </span><br><span class="line"> ++cur; <span class="comment">// 前进一步 </span></span><br><span class="line"> <span class="keyword">if</span> (cur == last) { <span class="comment">// 到了所在缓冲区的尾端了 </span></span><br><span class="line"> set_node(node + <span class="number">1</span>); <span class="comment">// 切换到下一个缓冲区 </span></span><br><span class="line"> cur = first; <span class="comment">// 的第一个元素 </span></span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">return</span> *<span class="keyword">this</span>; </span><br><span class="line"> } </span><br><span class="line"> self <span class="keyword">operator</span>++(<span class="keyword">int</span>) { </span><br><span class="line"> self tmp = *<span class="keyword">this</span>; </span><br><span class="line"> ++*<span class="keyword">this</span>; </span><br><span class="line"> <span class="keyword">return</span> tmp; </span><br><span class="line"> } </span><br><span class="line"> <span class="comment">//迭代器往回走一步。 </span></span><br><span class="line"> self& <span class="keyword">operator</span>--() { </span><br><span class="line"> <span class="keyword">if</span> (cur == first) { <span class="comment">// 如果在所在缓冲区的头部 </span></span><br><span class="line"> set_node(node - <span class="number">1</span>); <span class="comment">// 切换到前一个缓冲区 </span></span><br><span class="line"> cur = last; <span class="comment">// 的最后一个元素 </span></span><br><span class="line"> } </span><br><span class="line"> --cur; <span class="comment">// 直接往回走一步 </span></span><br><span class="line"> <span class="keyword">return</span> *<span class="keyword">this</span>; </span><br><span class="line"> } </span><br><span class="line"> self <span class="keyword">operator</span>--(<span class="keyword">int</span>) { </span><br><span class="line"> self tmp = *<span class="keyword">this</span>; </span><br><span class="line"> --*<span class="keyword">this</span>; </span><br><span class="line"> <span class="keyword">return</span> tmp; </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> <span class="comment">/* </span></span><br><span class="line"><span class="comment"> 迭代器向前进或后退n步(取决于n的正负)。这是支持random access iterator 所必须的操作。 </span></span><br><span class="line"><span class="comment"> 如果这个操作不会是迭代器走出当前所在缓冲区,直接更改cur即可。 </span></span><br><span class="line"><span class="comment"> 如果这个操作使迭代器走出当前所在缓冲区,要计算出操作后在哪个缓冲区的哪个位置。 </span></span><br><span class="line"><span class="comment"> */</span> </span><br><span class="line"> self& <span class="keyword">operator</span>+=(difference_type n) { </span><br><span class="line"> difference_type offset = n + (cur - first); </span><br><span class="line"> <span class="keyword">if</span> (offset >= <span class="number">0</span> && offset < difference_type(buffer_size())) </span><br><span class="line"> <span class="comment">// 不会走出当前所在缓冲区 </span></span><br><span class="line"> cur += n; </span><br><span class="line"> <span class="keyword">else</span> { </span><br><span class="line"> <span class="comment">// 走出了当前所在缓冲区 </span></span><br><span class="line"> difference_type node_offset = </span><br><span class="line"> offset > <span class="number">0</span> ? offset / difference_type(buffer_size()) </span><br><span class="line"> : -difference_type((-offset - <span class="number">1</span>) / buffer_size()) - <span class="number">1</span>; </span><br><span class="line"> <span class="comment">// 切换缓冲区 </span></span><br><span class="line"> set_node(node + node_offset); </span><br><span class="line"> <span class="comment">// 找到切换缓冲区后,迭代器所指向的元素 </span></span><br><span class="line"> cur = first + (offset - node_offset * difference_type(buffer_size())); </span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">return</span> *<span class="keyword">this</span>; </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> self <span class="keyword">operator</span>+(difference_type n) <span class="keyword">const</span> { </span><br><span class="line"> self tmp = *<span class="keyword">this</span>; </span><br><span class="line"> <span class="keyword">return</span> tmp += n; <span class="comment">// 调用operator+= </span></span><br><span class="line"> } </span><br><span class="line"> <span class="comment">//调用operator+= </span></span><br><span class="line"> self& <span class="keyword">operator</span>-=(difference_type n) { <span class="keyword">return</span> *<span class="keyword">this</span> += -n; } </span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> self <span class="keyword">operator</span>-(difference_type n) <span class="keyword">const</span> { </span><br><span class="line"> self tmp = *<span class="keyword">this</span>; </span><br><span class="line"> <span class="keyword">return</span> tmp -= n; <span class="comment">// 调用operator-= </span></span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> reference <span class="keyword">operator</span>[](difference_type n) <span class="keyword">const</span> { <span class="keyword">return</span> *(*<span class="keyword">this</span> + n); } </span><br><span class="line"> <span class="comment">// 以上调用了operator*, operator+ </span></span><br><span class="line"> </span><br><span class="line"> <span class="comment">/*迭代器关于比较的运算符的重载*/</span> </span><br><span class="line"> <span class="keyword">bool</span> <span class="keyword">operator</span>==(<span class="keyword">const</span> self& x) <span class="keyword">const</span> { <span class="keyword">return</span> cur == x.cur; } </span><br><span class="line"> <span class="keyword">bool</span> <span class="keyword">operator</span>!=(<span class="keyword">const</span> self& x) <span class="keyword">const</span> { <span class="keyword">return</span> !(*<span class="keyword">this</span> == x); } </span><br><span class="line"> <span class="keyword">bool</span> <span class="keyword">operator</span><(<span class="keyword">const</span> self& x) <span class="keyword">const</span> { </span><br><span class="line"> <span class="keyword">return</span> (node == x.node) ? (cur < x.cur) : (node < x.node); </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> <span class="comment">//切换缓冲区,更改了first和last,但是未更改cur </span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">set_node</span><span class="params">(map_pointer new_node)</span> </span>{ </span><br><span class="line"> node = new_node; </span><br><span class="line"> first = *new_node; </span><br><span class="line"> last = first + difference_type(buffer_size()); </span><br><span class="line"> } </span><br><span class="line">};</span><br></pre></td></tr></table></figure></p><p><img src="/imgs/stl_deque/deque_5.png" alt="5"></p><h1 id="deque的定义"><a href="#deque的定义" class="headerlink" title="deque的定义"></a>deque的定义</h1><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> <<span class="class"><span class="keyword">class</span> <span class="title">T</span>, <span class="title">class</span> <span class="title">Alloc</span> = <span class="title">alloc</span>, <span class="title">size_t</span> <span class="title">BufSiz</span> = 0> </span></span><br><span class="line"><span class="class"><span class="title">class</span> <span class="title">deque</span> {</span> </span><br><span class="line"><span class="keyword">public</span>: <span class="comment">// Basic types </span></span><br><span class="line"> <span class="keyword">typedef</span> T value_type; </span><br><span class="line"> <span class="keyword">typedef</span> value_type* pointer; </span><br><span class="line"> <span class="keyword">typedef</span> <span class="keyword">const</span> value_type* const_pointer; </span><br><span class="line"> <span class="keyword">typedef</span> value_type& reference; </span><br><span class="line"> <span class="keyword">typedef</span> <span class="keyword">const</span> value_type& const_reference; </span><br><span class="line"> <span class="keyword">typedef</span> <span class="keyword">size_t</span> size_type; </span><br><span class="line"> <span class="keyword">typedef</span> <span class="keyword">ptrdiff_t</span> difference_type; </span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span>: <span class="comment">// 迭代器 </span></span><br><span class="line"> <span class="keyword">typedef</span> __deque_iterator<T, T&, T*, BufSiz> iterator; </span><br><span class="line"> <span class="keyword">typedef</span> __deque_iterator<T, <span class="keyword">const</span> T&, <span class="keyword">const</span> T&, BufSiz> const_iterator; </span><br><span class="line"></span><br><span class="line"> <span class="keyword">typedef</span> reverse_iterator<const_iterator> const_reverse_iterator; </span><br><span class="line"> <span class="keyword">typedef</span> reverse_iterator<iterator> reverse_iterator; </span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"><span class="keyword">protected</span>: <span class="comment">// Internal typedefs </span></span><br><span class="line"> <span class="comment">// 指向中控器,是指针的指针(pointer of pointer of T) </span></span><br><span class="line"> <span class="keyword">typedef</span> pointer* map_pointer; </span><br><span class="line"> <span class="comment">// 空间配置器,用来配置缓冲区 </span></span><br><span class="line"> <span class="keyword">typedef</span> simple_alloc<value_type, Alloc> data_allocator; </span><br><span class="line"> <span class="comment">// 空间配置器,用来配置中控器 </span></span><br><span class="line"> <span class="keyword">typedef</span> simple_alloc<pointer, Alloc> map_allocator; </span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">static</span> size_type <span class="title">buffer_size</span><span class="params">()</span> </span>{ </span><br><span class="line"> <span class="keyword">return</span> __deque_buf_size(BufSiz, <span class="keyword">sizeof</span>(value_type)); </span><br><span class="line"> } </span><br><span class="line"> <span class="comment">//默认中控器大小为8 </span></span><br><span class="line"> <span class="function"><span class="keyword">static</span> size_type <span class="title">initial_map_size</span><span class="params">()</span> </span>{ <span class="keyword">return</span> <span class="number">8</span>; } </span><br><span class="line"> </span><br><span class="line"><span class="keyword">protected</span>: <span class="comment">// Data members </span></span><br><span class="line"> iterator start; <span class="comment">// start.cur指向deque的第一个结点 </span></span><br><span class="line"> iterator finish; <span class="comment">// finish.cur指向迭代器deque的最后一个结点的后一个元素 </span></span><br><span class="line"> </span><br><span class="line"> map_pointer <span class="built_in">map</span>; <span class="comment">// 指向中控器。其实是指向中控器的第一个结点。 </span></span><br><span class="line"> <span class="comment">// 中控器是连续的,map_size定义了中控器的大小。 </span></span><br><span class="line"> </span><br><span class="line"> size_type map_size; <span class="comment">// 中控器的大小。 </span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span>: <span class="comment">// 对外的接口 </span></span><br><span class="line"> <span class="function">iterator <span class="title">begin</span><span class="params">()</span> </span>{ <span class="keyword">return</span> start; } </span><br><span class="line"> <span class="function">iterator <span class="title">end</span><span class="params">()</span> </span>{ <span class="keyword">return</span> finish; } </span><br><span class="line"> <span class="function">const_iterator <span class="title">begin</span><span class="params">()</span> <span class="keyword">const</span> </span>{ <span class="keyword">return</span> start; } </span><br><span class="line"> <span class="function">const_iterator <span class="title">end</span><span class="params">()</span> <span class="keyword">const</span> </span>{ <span class="keyword">return</span> finish; } </span><br><span class="line"> </span><br><span class="line"> <span class="function">reverse_iterator <span class="title">rbegin</span><span class="params">()</span> </span>{ <span class="keyword">return</span> reverse_iterator(finish); } </span><br><span class="line"> <span class="function">reverse_iterator <span class="title">rend</span><span class="params">()</span> </span>{ <span class="keyword">return</span> reverse_iterator(start); } </span><br><span class="line"> <span class="function">const_reverse_iterator <span class="title">rbegin</span><span class="params">()</span> <span class="keyword">const</span> </span>{ </span><br><span class="line"> <span class="keyword">return</span> const_reverse_iterator(finish); </span><br><span class="line"> } </span><br><span class="line"> <span class="function">const_reverse_iterator <span class="title">rend</span><span class="params">()</span> <span class="keyword">const</span> </span>{ </span><br><span class="line"> <span class="keyword">return</span> const_reverse_iterator(start); </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> reference <span class="keyword">operator</span>[](size_type n) { </span><br><span class="line"> <span class="keyword">return</span> start[difference_type(n)]; <span class="comment">// 调用 __deque_iterator<>::operator[] </span></span><br><span class="line"> } </span><br><span class="line"> const_reference <span class="keyword">operator</span>[](size_type n) <span class="keyword">const</span> { </span><br><span class="line"> <span class="keyword">return</span> start[difference_type(n)]; </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> <span class="function">reference <span class="title">front</span><span class="params">()</span> </span>{ <span class="keyword">return</span> *start; } <span class="comment">// 调用 __deque_iterator<>::operator* </span></span><br><span class="line"> </span><br><span class="line"> <span class="comment">//取出最后一个元素 </span></span><br><span class="line"> <span class="function">reference <span class="title">back</span><span class="params">()</span> </span>{ </span><br><span class="line"> iterator tmp = finish; </span><br><span class="line"> --tmp; <span class="comment">// 调用 __deque_iterator<>::operator-- </span></span><br><span class="line"> <span class="keyword">return</span> *tmp; <span class="comment">// 调用 __deque_iterator<>::operator* </span></span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> <span class="comment">//返回第一个元素,并不删除 </span></span><br><span class="line"> <span class="function">const_reference <span class="title">front</span><span class="params">()</span> <span class="keyword">const</span> </span>{ <span class="keyword">return</span> *start; } </span><br><span class="line"> <span class="function">const_reference <span class="title">back</span><span class="params">()</span> <span class="keyword">const</span> </span>{ </span><br><span class="line"> const_iterator tmp = finish; </span><br><span class="line"> --tmp; </span><br><span class="line"> <span class="keyword">return</span> *tmp; </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> <span class="comment">//两分号但是合法</span></span><br><span class="line"> <span class="function">size_type <span class="title">size</span><span class="params">()</span> <span class="keyword">const</span> </span>{ <span class="keyword">return</span> finish - start;; } </span><br><span class="line"> <span class="comment">//deque最大容量。 </span></span><br><span class="line"> <span class="function">size_type <span class="title">max_size</span><span class="params">()</span> <span class="keyword">const</span> </span>{ <span class="keyword">return</span> size_type(<span class="number">-1</span>); } </span><br><span class="line"> <span class="comment">//下面调用了operator::iterator== </span></span><br><span class="line"> <span class="function"><span class="keyword">bool</span> <span class="title">empty</span><span class="params">()</span> <span class="keyword">const</span> </span>{ <span class="keyword">return</span> finish == start; } </span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span>: </span><br><span class="line"> </span><br><span class="line"> <span class="comment">//默认构造函数 </span></span><br><span class="line"> <span class="built_in">deque</span>(): start(), finish(), <span class="built_in">map</span>(<span class="number">0</span>), map_size(<span class="number">0</span>) </span><br><span class="line"> { </span><br><span class="line"> create_map_and_nodes(<span class="number">0</span>); </span><br><span class="line"> } </span><br><span class="line"><span class="comment">//用一个deque构建新的deque </span></span><br><span class="line"> <span class="built_in">deque</span>(<span class="keyword">const</span> <span class="built_in">deque</span>& x) </span><br><span class="line"> : start(), finish(), <span class="built_in">map</span>(<span class="number">0</span>), map_size(<span class="number">0</span>) </span><br><span class="line"> { </span><br><span class="line"> create_map_and_nodes(x.size()); </span><br><span class="line"> __STL_TRY { </span><br><span class="line"> uninitialized_copy(x.begin(), x.end(), start); </span><br><span class="line"> } </span><br><span class="line"> <span class="comment">//commit or rollback </span></span><br><span class="line"> __STL_UNWIND(destroy_map_and_nodes()); </span><br><span class="line"> } </span><br><span class="line"><span class="comment">//构建大小为n,元素值为value的deque </span></span><br><span class="line"> <span class="built_in">deque</span>(size_type n, <span class="keyword">const</span> value_type& value) </span><br><span class="line"> : start(), finish(), <span class="built_in">map</span>(<span class="number">0</span>), map_size(<span class="number">0</span>) </span><br><span class="line"> { </span><br><span class="line"> fill_initialize(n, value); </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> <span class="built_in">deque</span>(<span class="keyword">int</span> n, <span class="keyword">const</span> value_type& value) </span><br><span class="line"> : start(), finish(), <span class="built_in">map</span>(<span class="number">0</span>), map_size(<span class="number">0</span>) </span><br><span class="line"> { </span><br><span class="line"> fill_initialize(n, value); </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> <span class="built_in">deque</span>(<span class="keyword">long</span> n, <span class="keyword">const</span> value_type& value) </span><br><span class="line"> : start(), finish(), <span class="built_in">map</span>(<span class="number">0</span>), map_size(<span class="number">0</span>) </span><br><span class="line"> { </span><br><span class="line"> fill_initialize(n, value); </span><br><span class="line"> } </span><br><span class="line"><span class="comment">//构建大小为n的deque,默认值为T(),说明deque容器的元素要有默认构造函数 </span></span><br><span class="line"> <span class="function"><span class="keyword">explicit</span> <span class="title">deque</span><span class="params">(size_type n)</span> </span></span><br><span class="line"> : start(), finish(), map(0), map_size(0) </span><br><span class="line"> { </span><br><span class="line"> fill_initialize(n, value_type()); </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> <span class="keyword">template</span> <<span class="class"><span class="keyword">class</span> <span class="title">InputIterator</span>> </span></span><br><span class="line"><span class="class"> <span class="title">deque</span>(<span class="title">InputIterator</span> <span class="title">first</span>, <span class="title">InputIterator</span> <span class="title">last</span>) </span></span><br><span class="line"><span class="class"> :</span> start(), finish(), <span class="built_in">map</span>(<span class="number">0</span>), map_size(<span class="number">0</span>) </span><br><span class="line"> { </span><br><span class="line"> range_initialize(first, last, iterator_category(first)); </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> ~<span class="built_in">deque</span>() { </span><br><span class="line"> destroy(start, finish); </span><br><span class="line"> destroy_map_and_nodes(); </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> <span class="built_in">deque</span>& <span class="keyword">operator</span>= (<span class="keyword">const</span> <span class="built_in">deque</span>& x) { </span><br><span class="line"> <span class="keyword">const</span> size_type len = size(); </span><br><span class="line"> <span class="keyword">if</span> (&x != <span class="keyword">this</span>) { </span><br><span class="line"> <span class="keyword">if</span> (len >= x.size()) </span><br><span class="line"> erase(copy(x.begin(), x.end(), start), finish); </span><br><span class="line"> <span class="keyword">else</span> { </span><br><span class="line"> const_iterator mid = x.begin() + difference_type(len); </span><br><span class="line"> copy(x.begin(), mid, start); </span><br><span class="line"> insert(finish, mid, x.end()); </span><br><span class="line"> } </span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">return</span> *<span class="keyword">this</span>; </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">swap</span><span class="params">(<span class="built_in">deque</span>& x)</span> </span>{ </span><br><span class="line"> __STD::swap(start, x.start); </span><br><span class="line"> __STD::swap(finish, x.finish); </span><br><span class="line"> __STD::swap(<span class="built_in">map</span>, x.<span class="built_in">map</span>); </span><br><span class="line"> __STD::swap(map_size, x.map_size); </span><br><span class="line"> }</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h1 id="deque概述"><a href="#deque概述" class="headerlink" title="deque概述"></a>deque概述</h1><p>deque是一个双端队列</p>
</summary>
<category term="Summary" scheme="http://yoursite.com/categories/Summary/"/>
<category term="C++" scheme="http://yoursite.com/tags/C/"/>
<category term="STL" scheme="http://yoursite.com/tags/STL/"/>
<category term="list" scheme="http://yoursite.com/tags/list/"/>
</entry>
<entry>
<title>STL list ——part 2</title>
<link href="http://yoursite.com/2016/08/18/stl_list_2/"/>
<id>http://yoursite.com/2016/08/18/stl_list_2/</id>
<published>2016-08-17T16:31:32.000Z</published>
<updated>2019-04-30T13:25:38.091Z</updated>
<content type="html"><![CDATA[<h1 id="transfer、splice"><a href="#transfer、splice" class="headerlink" title="transfer、splice"></a>transfer、splice</h1><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//将first到last內的所有元素搬移到position 前,不包括last元素。 </span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">transfer</span><span class="params">(iterator position, iterator first, iterator last)</span> </span>{ </span><br><span class="line"> <span class="keyword">if</span> (position != last) { </span><br><span class="line"></span><br><span class="line"> (*(link_type((*last.node).prev))).next = position.node; </span><br><span class="line"> (*(link_type((*first.node).prev))).next = last.node; </span><br><span class="line"> (*(link_type((*position.node).prev))).next = first.node; </span><br><span class="line"> </span><br><span class="line"> link_type tmp = link_type((*position.node).prev); </span><br><span class="line"> (*position.node).prev = (*last.node).prev; </span><br><span class="line"> (*last.node).prev = (*first.node).prev; </span><br><span class="line"> (*first.node).prev = tmp; </span><br><span class="line"> } </span><br><span class="line">}</span><br></pre></td></tr></table></figure><a id="more"></a><p>迁移过程如图:<br><img src="/imgs/stl_list/transfer.png" alt="transfer"><br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 將 x 链表插入到 position 所指位置之前。x 必须不能是 *this。 </span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">splice</span><span class="params">(iterator position, <span class="built_in">list</span>& x)</span></span></span><br><span class="line"><span class="function"></span>{ </span><br><span class="line"> <span class="keyword">if</span> (!x.empty()) </span><br><span class="line"> transfer(position, x.begin(), x.end()); </span><br><span class="line">} </span><br><span class="line"><span class="comment">// 將i所指元素插入到 position 所指位置之前。position 和i 可在同一个list。 </span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">splice</span><span class="params">(iterator position, <span class="built_in">list</span>&, iterator i)</span></span></span><br><span class="line"><span class="function"></span>{ </span><br><span class="line"> iterator j = i; </span><br><span class="line"> ++j; </span><br><span class="line"> <span class="keyword">if</span> (position == i || position == j) <span class="keyword">return</span>; </span><br><span class="line"> transfer(position, i, j); </span><br><span class="line">} </span><br><span class="line"><span class="comment">// 將 [first,last) 內的所有元素插入到 position 所指位置之前。 </span></span><br><span class="line"><span class="comment">// position 和[first,last)可指在同一个list, </span></span><br><span class="line"><span class="comment">// 但position不能位于[first,last)之內。 </span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">splice</span><span class="params">(iterator position, <span class="built_in">list</span>&, iterator first, iterator last)</span></span></span><br><span class="line"><span class="function"></span>{ </span><br><span class="line"> <span class="keyword">if</span> (first != last) </span><br><span class="line"> transfer(position, first, last); </span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//将x合并到*this上面。两个链表都要先经过递增排序。相当于合并排序的最后一步 </span></span><br><span class="line"><span class="keyword">template</span> <<span class="class"><span class="keyword">class</span> <span class="title">T</span>, <span class="title">class</span> <span class="title">Alloc</span>> </span></span><br><span class="line"><span class="class"><span class="title">void</span> <span class="title">list</span><T, Alloc>:</span>:merge(<span class="built_in">list</span><T, Alloc>& x)</span><br><span class="line">{ </span><br><span class="line"> iterator first1 = begin(); </span><br><span class="line"> iterator last1 = end(); </span><br><span class="line"> iterator first2 = x.begin(); </span><br><span class="line"> iterator last2 = x.end(); </span><br><span class="line"> </span><br><span class="line"> <span class="comment">//前提是两个链表都已经递增排序好了 </span></span><br><span class="line"> <span class="keyword">while</span> (first1 != last1 && first2 != last2) </span><br><span class="line"> <span class="keyword">if</span> (*first2 < *first1) { </span><br><span class="line"> iterator next = first2; </span><br><span class="line"> transfer(first1, first2, ++next); </span><br><span class="line"> first2 = next; </span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> ++first1; </span><br><span class="line"> <span class="keyword">if</span> (first2 != last2) transfer(last1, first2, last2); </span><br><span class="line">} </span><br><span class="line"> </span><br><span class="line"><span class="comment">// 将 list逆置 </span></span><br><span class="line"><span class="keyword">template</span> <<span class="class"><span class="keyword">class</span> <span class="title">T</span>, <span class="title">class</span> <span class="title">Alloc</span>> </span></span><br><span class="line"><span class="class"><span class="title">void</span> <span class="title">list</span><T, Alloc>:</span>:reverse() </span><br><span class="line">{ </span><br><span class="line"> <span class="comment">//如果链表是空,或者只有一个元素,就不做任何处理 </span></span><br><span class="line"> <span class="comment">//不是用size()==0或size()==1来判断,因为这样比较慢 </span></span><br><span class="line"> <span class="keyword">if</span> (node->next == node || link_type(node->next)->next == node) <span class="keyword">return</span>; </span><br><span class="line"> iterator first = begin(); </span><br><span class="line"> ++first; </span><br><span class="line"> <span class="keyword">while</span> (first != end()) { </span><br><span class="line"> iterator old = first; </span><br><span class="line"> ++first; </span><br><span class="line"> transfer(begin(), old, first); </span><br><span class="line"> } </span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="list-sort"><a href="#list-sort" class="headerlink" title="list sort"></a>list sort</h1><p>list不能采用STL sort()算法,必须使用自己的sort;因为STL sort只能接收随机流迭代器<br>SGI实现版:<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> <<span class="class"><span class="keyword">class</span> <span class="title">T</span>, <span class="title">class</span> <span class="title">Alloc</span>> </span></span><br><span class="line"><span class="class"><span class="title">void</span> <span class="title">list</span><T, Alloc>:</span>:sort() { </span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> (node->next == node || link_type(node->next)->next == node) <span class="keyword">return</span>; </span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> <span class="built_in">list</span><T, Alloc> carry; </span><br><span class="line"> <span class="built_in">list</span><T, Alloc> counter[<span class="number">64</span>]; </span><br><span class="line"> </span><br><span class="line"> <span class="keyword">int</span> fill = <span class="number">0</span>; </span><br><span class="line"> <span class="keyword">while</span> (!empty()) </span><br><span class="line"> { </span><br><span class="line"> carry.splice(carry.begin(), *<span class="keyword">this</span>, begin()); <span class="comment">//取第一个放入carry中</span></span><br><span class="line"> <span class="keyword">int</span> i = <span class="number">0</span>; </span><br><span class="line"> <span class="keyword">while</span>(i < fill && !counter[i].empty()) <span class="comment">//counter[i]为空则跳过</span></span><br><span class="line"> { </span><br><span class="line"> counter[i].merge(carry); <span class="comment">//有序的合并到counter</span></span><br><span class="line"> carry.swap(counter[i++]); </span><br><span class="line"> } </span><br><span class="line"> carry.swap(counter[i]); <span class="comment">//将carry中的数据交换到counter[i]中</span></span><br><span class="line"> <span class="keyword">if</span> (i == fill) ++fill; </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i < fill; ++i) <span class="comment">//将数组中所有的数据合并到最后一个桶中</span></span><br><span class="line"> counter[i].merge(counter[i<span class="number">-1</span>]); </span><br><span class="line"> swap(counter[fill<span class="number">-1</span>]); </span><br><span class="line">} </span><br><span class="line"><span class="comment">//两个链表交换,就是他们的node头结点交换 </span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">swap</span><span class="params">(<span class="built_in">list</span><T, Alloc>& x)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">__STD::swap(node, x.node);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>sort的过程是一个循环归并的过程,定义一个tmp和一个list数组</p><pre><code>假设有这样以组数: 3 5 1 2 7 6 9 1.取 3 放入carry中,此时不满足循环条件i==fill,将carry中数据换入counter[0]中,carry为空,counter[0]为{3};2.取 5 放入carry中,carry与counter[0] merge并交换,得到counter为空,counter[1]为{3,5};3.取 1 放如carry中,此时counter[0]为空,不进入while循环,将 1 放入 counter[0]中,counter[0]为{1};4.去 2 放入carry中,和counter[0] merge 后又与counter[1] merge放入counter[2]中,counter[2]为{1,2,3,5}counter[0]和counter[1]为空;</code></pre><p>一直循环下去。。直到list为空。<br>然后最后面for循环将counter中的合并到最后一个中,在换给list,即完成了排序;</p>]]></content>
<summary type="html">
<h1 id="transfer、splice"><a href="#transfer、splice" class="headerlink" title="transfer、splice"></a>transfer、splice</h1><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//将first到last內的所有元素搬移到position 前,不包括last元素。 </span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">transfer</span><span class="params">(iterator position, iterator first, iterator last)</span> </span>&#123; </span><br><span class="line"> <span class="keyword">if</span> (position != last) &#123; </span><br><span class="line"></span><br><span class="line"> (*(link_type((*last.node).prev))).next = position.node; </span><br><span class="line"> (*(link_type((*first.node).prev))).next = last.node; </span><br><span class="line"> (*(link_type((*position.node).prev))).next = first.node; </span><br><span class="line"> </span><br><span class="line"> link_type tmp = link_type((*position.node).prev); </span><br><span class="line"> (*position.node).prev = (*last.node).prev; </span><br><span class="line"> (*last.node).prev = (*first.node).prev; </span><br><span class="line"> (*first.node).prev = tmp; </span><br><span class="line"> &#125; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</summary>
<category term="Summary" scheme="http://yoursite.com/categories/Summary/"/>
<category term="C++" scheme="http://yoursite.com/tags/C/"/>
<category term="STL" scheme="http://yoursite.com/tags/STL/"/>
<category term="list" scheme="http://yoursite.com/tags/list/"/>
</entry>
<entry>
<title>STL list ——part 1</title>
<link href="http://yoursite.com/2016/08/15/stl_list_1/"/>
<id>http://yoursite.com/2016/08/15/stl_list_1/</id>
<published>2016-08-15T15:19:53.000Z</published>
<updated>2019-04-30T13:25:27.727Z</updated>
<content type="html"><![CDATA[<h1 id="list结构"><a href="#list结构" class="headerlink" title="list结构"></a>list结构</h1><p>STL list是一个环形双向链表 ,结点结构如下:<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="class"><span class="keyword">class</span> <span class="title">T</span>></span></span><br><span class="line"><span class="class"><span class="title">struct</span> __<span class="title">list_node</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">void</span>* void_pointer;</span><br><span class="line">void_pointer prev;<span class="comment">//其实可以设为__list_node<T>*</span></span><br><span class="line">void_pointer next;</span><br><span class="line">T data;</span><br><span class="line">};</span><br></pre></td></tr></table></figure></p><a id="more"></a><h1 id="迭代器"><a href="#迭代器" class="headerlink" title="迭代器"></a>迭代器</h1><p>list是一个双向链表,其迭代器可以向前移、向后移,因此迭代器类型为bidirectional_iterator_tag<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 没有继承 std::iterator</span></span><br><span class="line"><span class="keyword">template</span><<span class="class"><span class="keyword">class</span> <span class="title">T</span>, <span class="title">class</span> <span class="title">Ref</span>, <span class="title">class</span> <span class="title">Ptr</span>> </span></span><br><span class="line"><span class="class"><span class="title">struct</span> __<span class="title">list_iterator</span> {</span> </span><br><span class="line"> <span class="keyword">typedef</span> __list_iterator<T, T&, T*> iterator; </span><br><span class="line"> <span class="keyword">typedef</span> __list_iterator<T, <span class="keyword">const</span> T&, <span class="keyword">const</span> T*> const_iterator; </span><br><span class="line"> <span class="keyword">typedef</span> __list_iterator<T, Ref, Ptr> self; </span><br><span class="line"> </span><br><span class="line"> <span class="comment">//为了支持STL型别标准,自己定义5个类别 </span></span><br><span class="line"> <span class="keyword">typedef</span> bidirectional_iterator_tag iterator_category; </span><br><span class="line"> <span class="keyword">typedef</span> T value_type; </span><br><span class="line"> <span class="keyword">typedef</span> Ptr pointer; </span><br><span class="line"> <span class="keyword">typedef</span> Ref reference; </span><br><span class="line"> <span class="keyword">typedef</span> <span class="keyword">ptrdiff_t</span> difference_type;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">typedef</span> __list_node<T>* link_type; </span><br><span class="line"> <span class="keyword">typedef</span> <span class="keyword">size_t</span> size_type; </span><br><span class="line"> </span><br><span class="line"> link_type node; <span class="comment">// 指向list的结点指针 </span></span><br><span class="line"> </span><br><span class="line"> <span class="comment">//构造函数 </span></span><br><span class="line"> __list_iterator(link_type x) : node(x) {} </span><br><span class="line"> __list_iterator() {} </span><br><span class="line"> __list_iterator(<span class="keyword">const</span> iterator& x) : node(x.node) {} </span><br><span class="line"> </span><br><span class="line"> <span class="comment">//迭代器操作运算符重载</span></span><br><span class="line"> <span class="keyword">bool</span> <span class="keyword">operator</span>==(<span class="keyword">const</span> self& x) <span class="keyword">const</span> { <span class="keyword">return</span> node == x.node; } </span><br><span class="line"> </span><br><span class="line"> <span class="keyword">bool</span> <span class="keyword">operator</span>!=(<span class="keyword">const</span> self& x) <span class="keyword">const</span> { <span class="keyword">return</span> node != x.node; } </span><br><span class="line"> </span><br><span class="line"> reference <span class="keyword">operator</span>*() <span class="keyword">const</span> { <span class="keyword">return</span> (*node).data; } </span><br><span class="line"> </span><br><span class="line"><span class="meta">#<span class="meta-keyword">ifndef</span> __SGI_STL_NO_ARROW_OPERATOR </span></span><br><span class="line"> pointer <span class="keyword">operator</span>->() <span class="keyword">const</span> { <span class="keyword">return</span> &(<span class="keyword">operator</span>*()); } </span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span> <span class="comment">/* __SGI_STL_NO_ARROW_OPERATOR */</span> </span></span><br><span class="line"> </span><br><span class="line"> self& <span class="keyword">operator</span>++() { </span><br><span class="line"> node = (link_type)((*node).next); </span><br><span class="line"> <span class="keyword">return</span> *<span class="keyword">this</span>; </span><br><span class="line"> } </span><br><span class="line"> self <span class="keyword">operator</span>++(<span class="keyword">int</span>) { </span><br><span class="line"> self tmp = *<span class="keyword">this</span>; </span><br><span class="line"> ++*<span class="keyword">this</span>; </span><br><span class="line"> <span class="keyword">return</span> tmp; </span><br><span class="line"> } </span><br><span class="line"> self& <span class="keyword">operator</span>--() { </span><br><span class="line"> node = (link_type)((*node).prev); </span><br><span class="line"> <span class="keyword">return</span> *<span class="keyword">this</span>; </span><br><span class="line"> } </span><br><span class="line"> self <span class="keyword">operator</span>--(<span class="keyword">int</span>) { </span><br><span class="line"> self tmp = *<span class="keyword">this</span>; </span><br><span class="line"> --*<span class="keyword">this</span>; </span><br><span class="line"> <span class="keyword">return</span> tmp; </span><br><span class="line"> } </span><br><span class="line">};</span><br></pre></td></tr></table></figure></p><h1 id="list-定义"><a href="#list-定义" class="headerlink" title="list 定义"></a>list 定义</h1><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> <<span class="class"><span class="keyword">class</span> <span class="title">T</span>, <span class="title">class</span> <span class="title">Alloc</span> = <span class="title">alloc</span>> // 默认为 <span class="title">alloc</span> 为配置器 </span></span><br><span class="line"><span class="class"><span class="title">class</span> <span class="title">list</span> {</span> </span><br><span class="line"><span class="keyword">protected</span>: </span><br><span class="line"> <span class="keyword">typedef</span> <span class="keyword">void</span>* void_pointer; </span><br><span class="line"> <span class="keyword">typedef</span> __list_node<T> list_node; </span><br><span class="line"> <span class="keyword">typedef</span> simple_alloc<list_node, Alloc> list_node_allocator; </span><br><span class="line"><span class="keyword">public</span>: </span><br><span class="line"> <span class="keyword">typedef</span> T value_type; </span><br><span class="line"> <span class="keyword">typedef</span> value_type* pointer; </span><br><span class="line"> <span class="keyword">typedef</span> <span class="keyword">const</span> value_type* const_pointer; </span><br><span class="line"> <span class="keyword">typedef</span> value_type& reference; </span><br><span class="line"> <span class="keyword">typedef</span> <span class="keyword">const</span> value_type& const_reference; </span><br><span class="line"> <span class="keyword">typedef</span> list_node* link_type; </span><br><span class="line"> <span class="keyword">typedef</span> <span class="keyword">size_t</span> size_type; </span><br><span class="line"> <span class="keyword">typedef</span> <span class="keyword">ptrdiff_t</span> difference_type; </span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span>: </span><br><span class="line"> <span class="keyword">typedef</span> __list_iterator<T, T&, T*> iterator; </span><br><span class="line"> <span class="keyword">typedef</span> __list_iterator<T, <span class="keyword">const</span> T&, <span class="keyword">const</span> T*> const_iterator; </span><br><span class="line"> </span><br><span class="line"><span class="meta">#<span class="meta-keyword">ifdef</span> __STL_CLASS_PARTIAL_SPECIALIZATION </span></span><br><span class="line"> <span class="keyword">typedef</span> reverse_iterator<const_iterator> const_reverse_iterator; </span><br><span class="line"> <span class="keyword">typedef</span> reverse_iterator<iterator> reverse_iterator; </span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span> <span class="comment">/* __STL_CLASS_PARTIAL_SPECIALIZATION */</span> </span></span><br><span class="line"> <span class="keyword">typedef</span> reverse_bidirectional_iterator<const_iterator, value_type, </span><br><span class="line"> const_reference, difference_type> </span><br><span class="line"> const_reverse_iterator; </span><br><span class="line"> <span class="keyword">typedef</span> reverse_bidirectional_iterator<iterator, value_type, reference, </span><br><span class="line"> difference_type> </span><br><span class="line"> reverse_iterator; </span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span> <span class="comment">/* __STL_CLASS_PARTIAL_SPECIALIZATION */</span> </span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">protected</span>: </span><br><span class="line"> <span class="comment">//申请、释放结点 </span></span><br><span class="line"> <span class="function">link_type <span class="title">get_node</span><span class="params">()</span> </span>{ <span class="keyword">return</span> list_node_allocator::allocate(); } </span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">put_node</span><span class="params">(link_type p)</span> </span>{ list_node_allocator::deallocate(p); } </span><br><span class="line"> </span><br><span class="line"> <span class="function">link_type <span class="title">create_node</span><span class="params">(<span class="keyword">const</span> T& x)</span> </span>{ </span><br><span class="line"> link_type p = get_node(); </span><br><span class="line"> __STL_TRY { </span><br><span class="line"> construct(&p->data, x); </span><br><span class="line"> } </span><br><span class="line"> __STL_UNWIND(put_node(p)); </span><br><span class="line"> <span class="keyword">return</span> p; </span><br><span class="line"> } </span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">destroy_node</span><span class="params">(link_type p)</span> </span>{ </span><br><span class="line"> destroy(&p->data); </span><br><span class="line"> put_node(p); </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"><span class="keyword">protected</span>: </span><br><span class="line"> <span class="comment">//初始化一个空链表,首尾相连 </span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">empty_initialize</span><span class="params">()</span> </span>{ </span><br><span class="line"> node = get_node(); </span><br><span class="line"> node->next = node; </span><br><span class="line"> node->prev = node; </span><br><span class="line"> } </span><br><span class="line"> <span class="comment">//初始化长为n的链表,值都为value </span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">fill_initialize</span><span class="params">(size_type n, <span class="keyword">const</span> T& value)</span> </span>{ </span><br><span class="line"> empty_initialize(); </span><br><span class="line"> __STL_TRY { </span><br><span class="line"> insert(begin(), n, value); <span class="comment">//先初始化一个空链表在插入n个结点</span></span><br><span class="line"> } </span><br><span class="line"> __STL_UNWIND(clear(); put_node(node)); </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"><span class="meta">#<span class="meta-keyword">ifdef</span> __STL_MEMBER_TEMPLATES </span></span><br><span class="line"> <span class="comment">//以迭代器区间初始化一个链表 </span></span><br><span class="line"> <span class="keyword">template</span> <<span class="class"><span class="keyword">class</span> <span class="title">InputIterator</span>> </span></span><br><span class="line"><span class="class"> <span class="title">void</span> <span class="title">range_initialize</span>(<span class="title">InputIterator</span> <span class="title">first</span>, <span class="title">InputIterator</span> <span class="title">last</span>) {</span> </span><br><span class="line"> empty_initialize(); </span><br><span class="line"> __STL_TRY { </span><br><span class="line"> insert(begin(), first, last); <span class="comment">//</span></span><br><span class="line"> } </span><br><span class="line"> <span class="comment">//commit or rollback </span></span><br><span class="line"> __STL_UNWIND(clear(); put_node(node)); </span><br><span class="line"> } </span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span> <span class="comment">/* __STL_MEMBER_TEMPLATES */</span> </span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">range_initialize</span><span class="params">(<span class="keyword">const</span> T* first, <span class="keyword">const</span> T* last)</span> </span>{ </span><br><span class="line"> empty_initialize(); </span><br><span class="line"> __STL_TRY { </span><br><span class="line"> insert(begin(), first, last); </span><br><span class="line"> } </span><br><span class="line"> __STL_UNWIND(clear(); put_node(node)); </span><br><span class="line"> } </span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">range_initialize</span><span class="params">(const_iterator first, const_iterator last)</span> </span>{ </span><br><span class="line"> empty_initialize(); </span><br><span class="line"> __STL_TRY { </span><br><span class="line"> insert(begin(), first, last); </span><br><span class="line"> } </span><br><span class="line"> __STL_UNWIND(clear(); put_node(node)); </span><br><span class="line"> } </span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span> <span class="comment">/* __STL_MEMBER_TEMPLATES */</span> </span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">protected</span>: </span><br><span class="line"> link_type node; <span class="comment">//头结点 </span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span>: </span><br><span class="line"> ...</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h1 id="list元素操作"><a href="#list元素操作" class="headerlink" title="list元素操作"></a>list元素操作</h1><h2 id="构造函数"><a href="#构造函数" class="headerlink" title="构造函数"></a>构造函数</h2><pre><code>list() { empty_initialize(); // 默认构造函数,空链表。//构造长为n的链表list(size_type n, const T& value) { fill_initialize(n, value); } list(int n, const T& value) { fill_initialize(n, value); } list(long n, const T& value) { fill_initialize(n, value); } explicit list(size_type n) { fill_initialize(n, T()); }//迭代器区间构造list template <class InputIterator> list(InputIterator first, InputIterator last){range_initialize(first, last);}//拷贝构造listlist(const list<T, Alloc>& x){range_initialize(x.begin(), x.end());} </code></pre><h2 id="push、pop、erase、insert、clear、remove、unique"><a href="#push、pop、erase、insert、clear、remove、unique" class="headerlink" title="push、pop、erase、insert、clear、remove、unique"></a>push、pop、erase、insert、clear、remove、unique</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br></pre></td><td class="code"><pre><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">push_front</span><span class="params">(<span class="keyword">const</span> T& x)</span> </span></span><br><span class="line"><span class="function"> </span>{ </span><br><span class="line"> insert(begin(), x); </span><br><span class="line"> } </span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">push_back</span><span class="params">(<span class="keyword">const</span> T& x)</span></span></span><br><span class="line"><span class="function"> </span>{ </span><br><span class="line"> insert(end(), x); </span><br><span class="line"> } </span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">pop_front</span><span class="params">()</span></span></span><br><span class="line"><span class="function"> </span>{ </span><br><span class="line"> erase(begin()); </span><br><span class="line"> } </span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">pop_back</span><span class="params">()</span></span></span><br><span class="line"><span class="function"> </span>{ </span><br><span class="line"> iterator tmp = end(); </span><br><span class="line"> erase(--tmp); </span><br><span class="line"> } </span><br><span class="line"> <span class="function">iterator <span class="title">insert</span><span class="params">(iterator position, <span class="keyword">const</span> T& x)</span> <span class="comment">//在postition所指位置之前插入一个结点</span></span></span><br><span class="line"><span class="function"> </span>{ </span><br><span class="line"> link_type tmp = create_node(x); <span class="comment">// 申请一个结点并用x初始化 </span></span><br><span class="line"> tmp->next = position.node; </span><br><span class="line"> tmp->prev = position.node->prev; </span><br><span class="line"> <span class="comment">//prev和next指针都是void*,所以需要指针类型转换 </span></span><br><span class="line"> (link_type(position.node->prev))->next = tmp; </span><br><span class="line"> position.node->prev = tmp; </span><br><span class="line"> <span class="keyword">return</span> tmp; </span><br><span class="line"> } </span><br><span class="line"> <span class="function">iterator <span class="title">erase</span><span class="params">(iterator position)</span> <span class="comment">//移除position所指结点 </span></span></span><br><span class="line"><span class="function"> </span>{ </span><br><span class="line"> link_type next_node = link_type(position.node->next); </span><br><span class="line"> link_type prev_node = link_type(position.node->prev); </span><br><span class="line"> prev_node->next = next_node; </span><br><span class="line"> next_node->prev = prev_node; </span><br><span class="line"> destroy_node(position.node); </span><br><span class="line"> <span class="keyword">return</span> iterator(next_node); </span><br><span class="line"> } </span><br><span class="line"><span class="keyword">template</span> <<span class="class"><span class="keyword">class</span> <span class="title">T</span>, <span class="title">class</span> <span class="title">Alloc</span>> </span></span><br><span class="line"><span class="class"><span class="title">void</span> <span class="title">list</span><T, Alloc>:</span>:clear() <span class="comment">// 清除所有结点 </span></span><br><span class="line">{ </span><br><span class="line"> link_type cur = (link_type) node->next; <span class="comment">// begin() </span></span><br><span class="line"> <span class="keyword">while</span> (cur != node) { <span class="comment">//遍历结点</span></span><br><span class="line"> link_type tmp = cur; </span><br><span class="line"> cur = (link_type) cur->next; </span><br><span class="line"> destroy_node(tmp); </span><br><span class="line"> } </span><br><span class="line"> <span class="comment">// 恢复头结点状态</span></span><br><span class="line"> node->next = node; </span><br><span class="line"> node->prev = node; </span><br><span class="line">} </span><br><span class="line"><span class="keyword">template</span> <<span class="class"><span class="keyword">class</span> <span class="title">T</span>, <span class="title">class</span> <span class="title">Alloc</span>> </span></span><br><span class="line"><span class="class"><span class="title">void</span> <span class="title">list</span><T, Alloc>:</span>:remove(<span class="keyword">const</span> T& value) <span class="comment">// 将数值为value的结点移除</span></span><br><span class="line">{ </span><br><span class="line"> iterator first = begin(); </span><br><span class="line"> iterator last = end(); </span><br><span class="line"> <span class="keyword">while</span> (first != last) { </span><br><span class="line"> iterator next = first; </span><br><span class="line"> ++next; </span><br><span class="line"> <span class="keyword">if</span> (*first == value) erase(first); <span class="comment">// 移除 </span></span><br><span class="line"> first = next; </span><br><span class="line"> } </span><br><span class="line">} </span><br><span class="line"><span class="keyword">template</span> <<span class="class"><span class="keyword">class</span> <span class="title">T</span>, <span class="title">class</span> <span class="title">Alloc</span>> </span></span><br><span class="line"><span class="class"><span class="title">void</span> <span class="title">list</span><T, Alloc>:</span>:unique()<span class="comment">// 移除数值相同的连续元素 ,只有相同的连续元素才会被移除!!</span></span><br><span class="line">{ </span><br><span class="line"> iterator first = begin(); </span><br><span class="line"> iterator last = end(); </span><br><span class="line"> <span class="keyword">if</span> (first == last) <span class="keyword">return</span>; </span><br><span class="line"> iterator next = first; </span><br><span class="line"> <span class="keyword">while</span> (++next != last) { </span><br><span class="line"> <span class="keyword">if</span> (*first == *next)</span><br><span class="line"> erase(next); </span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> first = next; </span><br><span class="line"> next = first; <span class="comment">//调整范围</span></span><br><span class="line"> } </span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="function">size_type <span class="title">size</span><span class="params">()</span> <span class="keyword">const</span> </span></span><br><span class="line"><span class="function"></span>{ </span><br><span class="line"> size_type result = <span class="number">0</span>; </span><br><span class="line"> distance(begin(), end(), result); <span class="comment">// 在<stl_iterator.h>定义,result是引用传递 </span></span><br><span class="line"> <span class="keyword">return</span> result; </span><br><span class="line"> }</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h1 id="list结构"><a href="#list结构" class="headerlink" title="list结构"></a>list结构</h1><p>STL list是一个环形双向链表 ,结点结构如下:<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span>&lt;<span class="class"><span class="keyword">class</span> <span class="title">T</span>&gt;</span></span><br><span class="line"><span class="class"><span class="title">struct</span> __<span class="title">list_node</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">void</span>* void_pointer;</span><br><span class="line">void_pointer prev;<span class="comment">//其实可以设为__list_node&lt;T&gt;*</span></span><br><span class="line">void_pointer next;</span><br><span class="line">T data;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></p>
</summary>
<category term="Summary" scheme="http://yoursite.com/categories/Summary/"/>
<category term="C++" scheme="http://yoursite.com/tags/C/"/>
<category term="STL" scheme="http://yoursite.com/tags/STL/"/>
<category term="list" scheme="http://yoursite.com/tags/list/"/>
</entry>
<entry>
<title>STL vector</title>
<link href="http://yoursite.com/2016/08/14/stl_vector/"/>
<id>http://yoursite.com/2016/08/14/stl_vector/</id>
<published>2016-08-13T17:53:03.000Z</published>
<updated>2019-04-30T13:25:59.371Z</updated>
<content type="html"><![CDATA[<h1 id="vector概述"><a href="#vector概述" class="headerlink" title="vector概述"></a>vector概述</h1><p> vector 数据安排上和数组非常相似,差别在于数组大小定义后不能在改变而vector内部会自行扩充空间容纳新元素</p><h1 id="vector-定义"><a href="#vector-定义" class="headerlink" title="vector 定义"></a>vector 定义</h1><a id="more"></a><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="class"><span class="keyword">class</span> _<span class="title">Ty</span>, <span class="title">class</span> _<span class="title">A</span> = <span class="title">allocator</span><_Ty> ></span></span><br><span class="line"><span class="class"><span class="title">class</span> <span class="title">vector</span> </span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"><span class="keyword">typedef</span> <span class="built_in">vector</span><_Ty, _A> _Myt;</span><br><span class="line"><span class="keyword">typedef</span> _A allocator_type;</span><br><span class="line"><span class="keyword">typedef</span> _A::size_type size_type;</span><br><span class="line"><span class="keyword">typedef</span> _A::difference_type difference_type;</span><br><span class="line"><span class="keyword">typedef</span> _A::pointer _Tptr;</span><br><span class="line"><span class="keyword">typedef</span> _A::const_pointer _Ctptr;</span><br><span class="line"><span class="keyword">typedef</span> _A::reference reference;</span><br><span class="line"><span class="keyword">typedef</span> _A::const_reference const_reference;</span><br><span class="line"><span class="keyword">typedef</span> _A::value_type value_type;</span><br><span class="line"><span class="keyword">typedef</span> _Tptr iterator; <span class="comment">//vector迭代器就是本身的指针</span></span><br><span class="line"><span class="keyword">typedef</span> _Ctptr const_iterator;</span><br><span class="line"></span><br><span class="line">protect:</span><br><span class="line">_A allocator; <span class="comment">//空间配置器</span></span><br><span class="line">iterator _First, _Last, _End;<span class="comment">//正在使用的头,正在使用的尾,空间的尾</span></span><br><span class="line">...</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h1 id="构造函数"><a href="#构造函数" class="headerlink" title="构造函数"></a>构造函数</h1><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">explicit</span> <span class="title">vector</span><span class="params">(<span class="keyword">const</span> _A& _Al = _A())</span> <span class="comment">//简单的初始化成员变量</span></span></span><br><span class="line">: allocator(_Al), _First(0), _Last(0), _End(0) {}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">explicit</span> <span class="title">vector</span><span class="params">(size_type _N, <span class="keyword">const</span> _Ty& _V = _Ty(), <span class="comment">//初始化_N个_TY变量</span></span></span></span><br><span class="line"><span class="function"><span class="params"><span class="keyword">const</span> _A& _Al = _A())</span></span></span><br><span class="line">: allocator(_Al)</span><br><span class="line">{_First = allocator.allocate(_N, (<span class="keyword">void</span> *)<span class="number">0</span>);</span><br><span class="line">_Ufill(_First, _N, _V); <span class="comment">//这个函数后面会有,就是从_F开始构造_N个_V </span></span><br><span class="line">_Last = _First + _N;</span><br><span class="line">_End = _Last; }</span><br><span class="line"></span><br><span class="line"><span class="built_in">vector</span>(<span class="keyword">const</span> _Myt& _X) <span class="comment">//拷贝构造函数</span></span><br><span class="line">: allocator(_X.allocator)</span><br><span class="line">{_First = allocator.allocate(_X.size(), (<span class="keyword">void</span> *)<span class="number">0</span>);</span><br><span class="line">_Last = _Ucopy(_X.begin(), _X.end(), _First);</span><br><span class="line">_End = _Last; }</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> const_iterator _It;</span><br><span class="line"><span class="built_in">vector</span>(_It _F, _It _L, <span class="keyword">const</span> _A& _Al = _A()) <span class="comment">//构造vector并在开始位置插入_F到_L间的数据</span></span><br><span class="line">: allocator(_Al), _First(<span class="number">0</span>), _Last(<span class="number">0</span>), _End(<span class="number">0</span>)</span><br><span class="line">{insert(begin(), _F, _L); }</span><br></pre></td></tr></table></figure><h1 id="vector-元素操作"><a href="#vector-元素操作" class="headerlink" title="vector 元素操作"></a>vector 元素操作</h1><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">resize</span><span class="params">(size_type _N, <span class="keyword">const</span> _Ty& _X = _Ty())</span> <span class="comment">//resize手动改变vector容量</span></span></span><br><span class="line"><span class="function"></span>{<span class="keyword">if</span> (size() < _N)</span><br><span class="line">insert(end(), _N - size(), _X);</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (_N < size())</span><br><span class="line">erase(begin() + _N, end()); }</span><br><span class="line"><span class="function">size_type <span class="title">size</span><span class="params">()</span> <span class="keyword">const</span> <span class="comment">//已用大小</span></span></span><br><span class="line"><span class="function"></span>{<span class="keyword">return</span> (_First == <span class="number">0</span> ? <span class="number">0</span> : _Last - _First); }</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">empty</span><span class="params">()</span> <span class="keyword">const</span></span></span><br><span class="line"><span class="function"></span>{<span class="keyword">return</span> (size() == <span class="number">0</span>); }</span><br><span class="line"></span><br><span class="line">reference <span class="keyword">operator</span>[](size_type _P)</span><br><span class="line">{<span class="keyword">return</span> (*(begin() + _P)); }</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">push_back</span><span class="params">(<span class="keyword">const</span> _Ty& _X)</span> <span class="comment">//在容器的最后插入一个元素</span></span></span><br><span class="line"><span class="function"></span>{insert(end(), _X); }</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">pop_back</span><span class="params">()</span> <span class="comment">//删除最后一个元素</span></span></span><br><span class="line"><span class="function"></span>{erase(end() - <span class="number">1</span>); }</span><br><span class="line"></span><br><span class="line"><span class="function">iterator <span class="title">insert</span><span class="params">(iterator _P, <span class="keyword">const</span> _Ty& _X = _Ty())</span> <span class="comment">//插入一个,返回的迭代器指向的是</span></span></span><br><span class="line"><span class="function"></span>{size_type _O = _P - begin();</span><br><span class="line">insert(_P, <span class="number">1</span>, _X);</span><br><span class="line"><span class="keyword">return</span> (begin() + _O); }</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">insert</span><span class="params">(iterator _P, size_type _M, <span class="keyword">const</span> _Ty& _X)</span> <span class="comment">//从_P开始插入_M个_X元素</span></span></span><br><span class="line"><span class="function"></span>{<span class="keyword">if</span> (_End - _Last < _M)</span><br><span class="line">{size_type _N = size() + (_M < size() ? size() : _M);</span><br><span class="line">iterator _S = allocator.allocate(_N, (<span class="keyword">void</span> *)<span class="number">0</span>);</span><br><span class="line">iterator _Q = _Ucopy(_First, _P, _S);</span><br><span class="line">_Ufill(_Q, _M, _X);</span><br><span class="line">_Ucopy(_P, _Last, _Q + _M);</span><br><span class="line">_Destroy(_First, _Last);</span><br><span class="line">allocator.deallocate(_First, _End - _First);</span><br><span class="line">_End = _S + _N;</span><br><span class="line">_Last = _S + size() + _M;</span><br><span class="line">_First = _S; }</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (_Last - _P < _M)</span><br><span class="line">{_Ucopy(_P, _Last, _P + _M);</span><br><span class="line">_Ufill(_Last, _M - (_Last - _P), _X);</span><br><span class="line">fill(_P, _Last, _X);</span><br><span class="line">_Last += _M; }</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (<span class="number">0</span> < _M)</span><br><span class="line">{_Ucopy(_Last - _M, _Last, _Last);</span><br><span class="line">copy_backward(_P, _Last - _M, _Last);</span><br><span class="line">fill(_P, _P + _M, _X);</span><br><span class="line">_Last += _M; }}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">insert</span><span class="params">(iterator _P, _It _F, _It _L)</span></span></span><br><span class="line"><span class="function"></span>{size_type _M = <span class="number">0</span>;</span><br><span class="line">_Distance(_F, _L, _M);</span><br><span class="line"><span class="keyword">if</span> (_End - _Last < _M)</span><br><span class="line">{size_type _N = size() + (_M < size() ? size() : _M);</span><br><span class="line">iterator _S = allocator.allocate(_N, (<span class="keyword">void</span> *)<span class="number">0</span>);</span><br><span class="line">iterator _Q = _Ucopy(_First, _P, _S);</span><br><span class="line">_Q = _Ucopy(_F, _L, _Q);</span><br><span class="line">_Ucopy(_P, _Last, _Q);</span><br><span class="line">_Destroy(_First, _Last);</span><br><span class="line">allocator.deallocate(_First, _End - _First);</span><br><span class="line">_End = _S + _N;</span><br><span class="line">_Last = _S + size() + _M;</span><br><span class="line">_First = _S; }</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (_Last - _P < _M)</span><br><span class="line">{_Ucopy(_P, _Last, _P + _M);</span><br><span class="line">_Ucopy(_F + (_Last - _P), _L, _Last);</span><br><span class="line">copy(_F, _F + (_Last - _P), _P);</span><br><span class="line">_Last += _M; }</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (<span class="number">0</span> < _M)</span><br><span class="line">{_Ucopy(_Last - _M, _Last, _Last);</span><br><span class="line">copy_backward(_P, _Last - _M, _Last);</span><br><span class="line">copy(_F, _L, _P);</span><br><span class="line">_Last += _M; }}</span><br><span class="line"><span class="function">iterator <span class="title">erase</span><span class="params">(iterator _P)</span></span></span><br><span class="line"><span class="function"></span>{copy(_P + <span class="number">1</span>, end(), _P); <span class="comment">// 从—_p+1开始往前挪</span></span><br><span class="line">_Destroy(_Last - <span class="number">1</span>, _Last);</span><br><span class="line">--_Last;</span><br><span class="line"><span class="keyword">return</span> (_P); }</span><br><span class="line"><span class="function">iterator <span class="title">erase</span><span class="params">(iterator _F, iterator _L)</span></span></span><br><span class="line"><span class="function"></span>{iterator _S = copy(_L, end(), _F);</span><br><span class="line">_Destroy(_S, end());</span><br><span class="line">_Last = _S;</span><br><span class="line"><span class="keyword">return</span> (_F); }</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">clear</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{erase(begin(), end()); }</span><br><span class="line"></span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line"><span class="keyword">void</span> _Destroy(iterator _F, iterator _L)</span><br><span class="line">{<span class="keyword">for</span> (; _F != _L; ++_F)</span><br><span class="line">allocator.destroy(_F); }</span><br><span class="line">iterator _Ucopy(const_iterator _F, const_iterator _L,</span><br><span class="line">iterator _P)</span><br><span class="line">{<span class="keyword">for</span> (; _F != _L; ++_P, ++_F)</span><br><span class="line">allocator.construct(_P, *_F);</span><br><span class="line"><span class="keyword">return</span> (_P); }</span><br><span class="line"><span class="keyword">void</span> _Ufill(iterator _F, size_type _N, <span class="keyword">const</span> _Ty &_X)</span><br><span class="line">{<span class="keyword">for</span> (; <span class="number">0</span> < _N; --_N, ++_F)</span><br><span class="line">allocator.construct(_F, _X); }</span><br><span class="line"><span class="keyword">void</span> _Xran() <span class="keyword">const</span></span><br><span class="line">{_THROW(out_of_range, <span class="string">"invalid vector<T> subscript"</span>); }</span><br><span class="line"></span><br><span class="line"><span class="function">size_type <span class="title">capacity</span><span class="params">()</span> <span class="keyword">const</span> <span class="comment">//容量</span></span></span><br><span class="line"><span class="function"></span>{<span class="keyword">return</span> (_First == <span class="number">0</span> ? <span class="number">0</span> : _End - _First); }</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h1 id="vector概述"><a href="#vector概述" class="headerlink" title="vector概述"></a>vector概述</h1><p> vector 数据安排上和数组非常相似,差别在于数组大小定义后不能在改变而vector内部会自行扩充空间容纳新元素</p>
<h1 id="vector-定义"><a href="#vector-定义" class="headerlink" title="vector 定义"></a>vector 定义</h1>
</summary>
<category term="Summary" scheme="http://yoursite.com/categories/Summary/"/>
<category term="C++" scheme="http://yoursite.com/tags/C/"/>
<category term="STL" scheme="http://yoursite.com/tags/STL/"/>
<category term="vector" scheme="http://yoursite.com/tags/vector/"/>
</entry>
<entry>
<title>STL traits</title>
<link href="http://yoursite.com/2016/08/10/stl_traits/"/>
<id>http://yoursite.com/2016/08/10/stl_traits/</id>
<published>2016-08-10T04:56:46.000Z</published>
<updated>2019-04-30T13:25:48.639Z</updated>
<content type="html"><![CDATA[<h1 id="STL-traits的实现"><a href="#STL-traits的实现" class="headerlink" title="STL traits的实现"></a>STL traits的实现</h1><pre><code>traits 是一种能获取出你所需类型特性的方法:</code></pre><a id="more"></a><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">input_iterator_tag</span>{</span>};</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">output_iterator_tag</span>{</span>};</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">forward_iterator_tag</span> :</span><span class="keyword">public</span> input_iterator_tag{};</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">bidirectional_iterator_tag</span>:</span> <span class="keyword">public</span> forward_iterator_tag{};</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">random_access_iterator_tag</span>:</span> <span class="keyword">public</span> bidirectional_iterator_tag{};</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span><<span class="class"><span class="keyword">class</span> _<span class="title">Cat</span>,<span class="title">class</span> _<span class="title">T</span>,<span class="title">class</span> _<span class="title">Dis</span> = <span class="title">int</span>,</span></span><br><span class="line"><span class="class"> <span class="title">class</span> _<span class="title">P</span> = _<span class="title">T</span>*, <span class="title">class</span> _<span class="title">Ref</span> = _<span class="title">T</span>&></span></span><br><span class="line"><span class="class"><span class="title">struct</span> <span class="title">iterator</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">typedef</span> _Cat iterator_category;</span><br><span class="line"><span class="keyword">typedef</span> _T value_type;</span><br><span class="line"><span class="keyword">typedef</span> _Dis difference_type;</span><br><span class="line"><span class="keyword">typedef</span> _P pointer;</span><br><span class="line"><span class="keyword">typedef</span> _Ref reference;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span><<span class="class"><span class="keyword">class</span> <span class="title">Iterator</span>></span></span><br><span class="line"><span class="class"><span class="title">struct</span> <span class="title">iterator_traits</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">typename</span> Iterator::iterator_category iterator_category;</span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">typename</span> Iterator::value_type value_type;</span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">typename</span> Iterator::difference_type difference_type;</span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">typename</span> Iterator::pointer pointer;</span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">typename</span> Iterator::reference reference;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span><<span class="class"><span class="keyword">class</span> <span class="title">T</span>></span></span><br><span class="line"><span class="class"><span class="title">struct</span> <span class="title">iterator_traits</span><T*></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">typedef</span> random_access_iterator_tag iterator_category;</span><br><span class="line"><span class="keyword">typedef</span> T value_type;</span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">int</span> difference_type;</span><br><span class="line"><span class="keyword">typedef</span> T * pointer;</span><br><span class="line"><span class="keyword">typedef</span> T & reference;</span><br><span class="line">};</span><br><span class="line"><span class="keyword">template</span><<span class="class"><span class="keyword">class</span> <span class="title">T</span>></span></span><br><span class="line"><span class="class"><span class="title">struct</span> <span class="title">iterator_traits</span><const T*></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">typedef</span> random_access_iterator_tag iterator_category;</span><br><span class="line"><span class="keyword">typedef</span> T value_type;</span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">int</span> difference_type;</span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">const</span> T * pointer;</span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">const</span> T & reference;</span><br><span class="line">};</span><br><span class="line"><span class="keyword">template</span><<span class="class"><span class="keyword">class</span> <span class="title">Iterator</span>></span></span><br><span class="line"><span class="class"><span class="title">typename</span> <span class="title">iterator_traits</span><Iterator>:</span>:iterator_category</span><br><span class="line">iterator_category(Iterator &) <span class="comment">//迭代器的'类型'</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">typename</span> iterator_traits<Iterator>::iterator_category iterator_category;</span><br><span class="line"><span class="keyword">return</span> iterator_category();</span><br><span class="line">}</span><br><span class="line"><span class="keyword">template</span><<span class="class"><span class="keyword">class</span> <span class="title">Iterator</span>></span></span><br><span class="line"><span class="class"><span class="title">typename</span> <span class="title">iterator_traits</span><Iterator>:</span>:value_type*</span><br><span class="line">value_type(Iterator &) <span class="comment">//迭代器所指之物类型</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">static_cast</span><<span class="keyword">typename</span> iterator_traits<Iterator>::value_type*>(<span class="number">0</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span><<span class="class"><span class="keyword">class</span> <span class="title">Iterator</span>></span></span><br><span class="line"><span class="class"><span class="title">typename</span> <span class="title">iterator_traits</span><Iterator>:</span>:difference_type *</span><br><span class="line">difference_type(Iterator &) <span class="comment">//获取差值类型</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">return</span> <span class="keyword">static_cast</span><<span class="keyword">typename</span> iterator_traits<Iterator>::difference_type*>(<span class="number">0</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="迭代器分类"><a href="#迭代器分类" class="headerlink" title="迭代器分类"></a>迭代器分类</h1><p><img src="/imgs/Summary/stl_iterator.png" alt="stl_iterator"><br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">input_iterator_tag</span>{</span>};</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">output_iterator_tag</span>{</span>};</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">forward_iterator_tag</span> :</span><span class="keyword">public</span> input_iterator_tag{};</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">bidirectional_iterator_tag</span>:</span> <span class="keyword">public</span> forward_iterator_tag{};</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">random_access_iterator_tag</span>:</span> <span class="keyword">public</span> bidirectional_iterator_tag{};</span><br></pre></td></tr></table></figure></p><h1 id="advance例子"><a href="#advance例子" class="headerlink" title="advance例子"></a>advance例子</h1><p><img src="/imgs/Summary/stl_traits.png" alt="stl_traits"></p>]]></content>
<summary type="html">
<h1 id="STL-traits的实现"><a href="#STL-traits的实现" class="headerlink" title="STL traits的实现"></a>STL traits的实现</h1><pre><code>traits 是一种能获取出你所需类型特性的方法:
</code></pre>
</summary>
<category term="Summary" scheme="http://yoursite.com/categories/Summary/"/>
<category term="C++" scheme="http://yoursite.com/tags/C/"/>
<category term="STL" scheme="http://yoursite.com/tags/STL/"/>
<category term="traits" scheme="http://yoursite.com/tags/traits/"/>
</entry>
<entry>
<title>可变参函数</title>
<link href="http://yoursite.com/2016/08/06/stdarg/"/>
<id>http://yoursite.com/2016/08/06/stdarg/</id>
<published>2016-08-06T06:33:58.000Z</published>
<updated>2019-04-30T13:24:50.005Z</updated>
<content type="html"><![CDATA[<h1 id="使用示例"><a href="#使用示例" class="headerlink" title="使用示例"></a>使用示例</h1><p><img src="/imgs/Summary/stdargs.png" alt="stdargs"></p><h1 id="实现原理"><a href="#实现原理" class="headerlink" title="实现原理"></a>实现原理</h1><h2 id="va-list"><a href="#va-list" class="headerlink" title="va_list"></a>va_list</h2><pre><code>va_list 是一个字符指针类型。typedef char *va_list; </code></pre><a id="more"></a><h2 id="va-start"><a href="#va-start" class="headerlink" title="va_start"></a>va_start</h2><p>va_start用于初始化 va_list, 取第一个参数(从左向右)的地址再向高地址偏移LASTARG大小,实际上指向了第二个参数(从左向右)</p><pre><code>#ifndef __sparc__#define va_start(AP, LASTARG) \(AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG))) //AP即va_list#else#define va_start(AP, LASTARG) \(__builtin_saveregs (), \AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))#endif__builtin_saveregs()是在gcc 的库程序libgcc2.c 中定义的,用于保存寄存器。它的说明可参见gcc 手册章节“Target Description Macros”中的“Implementing the Varargs Macros”小节。</code></pre><h3 id="va-rounded-size"><a href="#va-rounded-size" class="headerlink" title="__va_rounded_size"></a>__va_rounded_size</h3><p>__va_rounded_size定义了取整后的TYPE 类型的字节长度值。是int 长度(4)的倍数。</p><pre><code>#define __va_rounded_size(TYPE) \(((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))</code></pre><h2 id="va-arg"><a href="#va-arg" class="headerlink" title="va_arg"></a>va_arg</h2><p>va_arg先让AP偏移到指向下一个参数的位置,再返回要取的参数</p><pre><code>#define va_arg(AP, TYPE) \(AP += __va_rounded_size (TYPE), \*((TYPE *) (AP - __va_rounded_size (TYPE))))</code></pre><h2 id="va-end"><a href="#va-end" class="headerlink" title="va_end"></a>va_end</h2><p>va_end 必须在va_arg 读完所有的参数后再被调用。<br>va_end 可以修改AP 使其在重新调用va_start 之前不能被使用(把va_list指向NULL)。<br> void va_end (va_list); // 在gnulib 中定义</p><pre><code>#define va_end(AP)</code></pre><h1 id="Linux内核代码Acenv-h中也定义了一组宏"><a href="#Linux内核代码Acenv-h中也定义了一组宏" class="headerlink" title="Linux内核代码Acenv.h中也定义了一组宏"></a>Linux内核代码Acenv.h中也定义了一组宏</h1><p><img src="/imgs/Summary/linux_args.png" alt="linuxstdargs"></p>]]></content>
<summary type="html">
<h1 id="使用示例"><a href="#使用示例" class="headerlink" title="使用示例"></a>使用示例</h1><p><img src="/imgs/Summary/stdargs.png" alt="stdargs"></p>
<h1 id="实现原理"><a href="#实现原理" class="headerlink" title="实现原理"></a>实现原理</h1><h2 id="va-list"><a href="#va-list" class="headerlink" title="va_list"></a>va_list</h2><pre><code>va_list 是一个字符指针类型。
typedef char *va_list;
</code></pre>
</summary>
<category term="Summary" scheme="http://yoursite.com/categories/Summary/"/>
<category term="C" scheme="http://yoursite.com/tags/C/"/>
<category term="stdargs" scheme="http://yoursite.com/tags/stdargs/"/>
</entry>
<entry>
<title>最长公共子序列</title>
<link href="http://yoursite.com/2016/06/23/lcs/"/>
<id>http://yoursite.com/2016/06/23/lcs/</id>
<published>2016-06-23T04:18:38.000Z</published>
<updated>2019-04-30T13:24:36.789Z</updated>
<content type="html"><![CDATA[<h1 id="最长公共子序列(LongestCommonSubsequence)"><a href="#最长公共子序列(LongestCommonSubsequence)" class="headerlink" title="最长公共子序列(LongestCommonSubsequence)"></a>最长公共子序列(LongestCommonSubsequence)</h1><p>一个数列S,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则S称为已知序列的最长公共子序列。<br>最长公共子序列问题可以由动态规划求解</p><h1 id="动态规划"><a href="#动态规划" class="headerlink" title="动态规划"></a>动态规划</h1><p>动态规划(英语:Dynamic programming,简称DP)是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。<br>动态规划常常适用于有重叠子问题和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。<br>动态规划背后的基本思想非常简单。大致上,若要解一个给定问题,我们需要解其不同部分(即子问题),再合并子问题的解以得出原问题的解。<br>通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量:一旦某个给定子问题的解已经算出,则将其记忆化(en:memoization)存储,以便下次需要同一个子问题解之时直接查表。这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用。————<a href="https://zh.wikipedia.org/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92" target="_blank" rel="noopener">维基百科</a></p><h1 id="动态规划求解LCS"><a href="#动态规划求解LCS" class="headerlink" title="动态规划求解LCS"></a>动态规划求解LCS</h1><a id="more"></a><h3 id="1-最优子结构性质"><a href="#1-最优子结构性质" class="headerlink" title="1.最优子结构性质"></a>1.最优子结构性质</h3><p>设输入序列是X [0 .. m-1] 和 Y [0 .. n-1],长度分别为 m 和 n。和设序列 L(X [0 .. m-1],Y[0 .. n-1]) 是这两个序列的 LCS 的长度,以下为 L(X [0 .. M-1],Y [0 .. N-1]) 的递归定义:</p><pre><code>1)如果两个序列的最后一个元素匹配(即X [M-1] == Y [N-1])</code></pre><p> 则:L(X [0 .. M-1],Y [0 .. N-1])= 1 + L(X [0 .. M-2],Y [0 .. N-1])</p><pre><code>2)如果两个序列的最后字符不匹配(即X [M-1] != Y [N-1])</code></pre><p> 则:L(X [0 .. M-1],Y [0 .. N-1]) = MAX(L(X [0 .. M-2],Y [0 .. N-1]),L(X [0 .. M-1],Y [0 .. N-2]))</p><h3 id="2-重叠子问题"><a href="#2-重叠子问题" class="headerlink" title="2.重叠子问题"></a>2.重叠子问题</h3><pre><code>很明显,LCS 很多子问题也都共享子子问题,因此可以对其进行递归求解。具体的算法时间度为 O(m*n),可以优化至 O(m+n)。</code></pre><h1 id="code"><a href="#code" class="headerlink" title="code"></a>code</h1><p>代码如下:</p><h3 id="未优化"><a href="#未优化" class="headerlink" title="未优化"></a>未优化</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">int Longest_Common_Subsequence(char *sa, int n1, char *sb, int n2)</span><br><span class="line">{</span><br><span class="line">if (n1 > 0 && n2 > 0)</span><br><span class="line">{</span><br><span class="line">if (sa[n1 - 1] == sb[n2 - 1]) </span><br><span class="line">return 1 + Longest_Common_Subsequence(sa, n1 - 1, sb, n2 - 1);</span><br><span class="line">else </span><br><span class="line">return max(Longest_Common_Subsequence(sa, n1 , sb, n2 - 1),</span><br><span class="line">Longest_Common_Subsequence(sa, n1 - 1, sb, n2 ));</span><br><span class="line">}</span><br><span class="line">return 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="优化后"><a href="#优化后" class="headerlink" title="优化后"></a>优化后</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">int lcs(char *sa, int n1, char *sb, int n2)</span><br><span class="line">{</span><br><span class="line">int **ls = new int*[n1];</span><br><span class="line">for (int i = 0; i < n1; ++i)</span><br><span class="line">{</span><br><span class="line">ls[i] = new int[n2];</span><br><span class="line">}</span><br><span class="line">for (int i = 0; i < n1; ++i)</span><br><span class="line">{</span><br><span class="line">for (int j = 0; j < n2; ++j)</span><br><span class="line">{</span><br><span class="line">if (i == 0 || j == 0) ls[i][j] = 0;</span><br><span class="line">else if (sa[i - 1] == sb[j - 1]) ls[i][j] = ls[i - 1][j - 1] + 1;</span><br><span class="line">else ls[i][j] = max(ls[i - 1][j], ls[i][j - 1]);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">int tmp = ls[n1 - 1][n2 - 1];</span><br><span class="line">for (int k = 0; k < n1; ++k)</span><br><span class="line">{</span><br><span class="line">delete []ls[k];</span><br><span class="line">}</span><br><span class="line">delete []ls;</span><br><span class="line">return tmp;</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h1 id="最长公共子序列(LongestCommonSubsequence)"><a href="#最长公共子序列(LongestCommonSubsequence)" class="headerlink" title="最长公共子序列(LongestCommonSubsequence)"></a>最长公共子序列(LongestCommonSubsequence)</h1><p>一个数列S,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则S称为已知序列的最长公共子序列。<br>最长公共子序列问题可以由动态规划求解</p>
<h1 id="动态规划"><a href="#动态规划" class="headerlink" title="动态规划"></a>动态规划</h1><p>动态规划(英语:Dynamic programming,简称DP)是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。<br>动态规划常常适用于有重叠子问题和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。<br>动态规划背后的基本思想非常简单。大致上,若要解一个给定问题,我们需要解其不同部分(即子问题),再合并子问题的解以得出原问题的解。<br>通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量:一旦某个给定子问题的解已经算出,则将其记忆化(en:memoization)存储,以便下次需要同一个子问题解之时直接查表。这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用。————<a href="https://zh.wikipedia.org/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92" target="_blank" rel="noopener">维基百科</a></p>
<h1 id="动态规划求解LCS"><a href="#动态规划求解LCS" class="headerlink" title="动态规划求解LCS"></a>动态规划求解LCS</h1>
</summary>
<category term="Algorithm" scheme="http://yoursite.com/categories/Algorithm/"/>
<category term="LongestCommonSubsequence" scheme="http://yoursite.com/tags/LongestCommonSubsequence/"/>
<category term="Dynamic_Programming" scheme="http://yoursite.com/tags/Dynamic-Programming/"/>
</entry>
<entry>
<title>C++11</title>
<link href="http://yoursite.com/2016/06/20/C++11/"/>
<id>http://yoursite.com/2016/06/20/C++11/</id>
<published>2016-06-19T17:14:38.000Z</published>
<updated>2016-07-23T17:29:04.000Z</updated>
<content type="html"><![CDATA[<h1 id="auto"><a href="#auto" class="headerlink" title="auto"></a>auto</h1><p>auto是C++程序设计语言的关键字。自C++11以来,auto关键字用于两种情况:声明变量时根据初始化表达式自动推断该变量的类型、声明函数时函数返回值的占位符。C++98标准中auto关键字用于自动变量的声明,但由于使用极少且多余,在C++11中已删除这一用法。–维基百科<br>auto实际上实在编译时对变量进行了类型推导,似乎auto并不会影响编译速度,因为编译时本来也要右侧推导然后判断与左侧是否匹配。<br>从汇编看也是如此:<br><img src="/imgs/Summary/int.png" alt="int"><br><img src="/imgs/Summary/auto_int.png" alt="auto_int"><br>自定义类型<br><img src="/imgs/Summary/A.png" alt="A"><br><img src="/imgs/Summary/auto_A.png" alt="auto_A"><br>auto用于模板简化了模板的操作<br><img src="/imgs/Summary/auto_template.png" alt="auto_template"></p><h1 id="lambda表达式"><a href="#lambda表达式" class="headerlink" title="lambda表达式"></a>lambda表达式</h1><p>它可以用于创建并定义匿名的函数对象形式如下:<br>[函数对象参数](操作符重载函数参数) ->返回值类型{函数体}(具体参数)<br><img src="/imgs/Summary/lambda.png" alt="lambda"></p><h1 id="decltype"><a href="#decltype" class="headerlink" title="decltype"></a>decltype</h1><p>decltype的功能与auto相反,从变量得到类型<br><img src="/imgs/Summary/decltype.png" alt="decltype"></p><h1 id="右值引用"><a href="#右值引用" class="headerlink" title="右值引用"></a>右值引用</h1><p>右值引用(rvalue reference),是C++程序设计语言自C++11标准提出的一类数据类型。用于实现移动语义(move semantic)与完美转发(perfect forwarding)。–维基百科<br>在资源转移不是调用拷贝等操作而是实现了资源的转移<br><a href="https://www.zhihu.com/question/22111546" target="_blank" rel="noopener">参考</a></p>]]></content>
<summary type="html">
<h1 id="auto"><a href="#auto" class="headerlink" title="auto"></a>auto</h1><p>auto是C++程序设计语言的关键字。自C++11以来,auto关键字用于两种情况:声明变量时根据初始化表达式自动推断该变量
</summary>
<category term="Summary" scheme="http://yoursite.com/categories/Summary/"/>
<category term="C++11" scheme="http://yoursite.com/tags/C-11/"/>
<category term="C++" scheme="http://yoursite.com/tags/C/"/>
</entry>
<entry>
<title>STL空间配置器</title>
<link href="http://yoursite.com/2016/06/12/stl_alloc/"/>
<id>http://yoursite.com/2016/06/12/stl_alloc/</id>
<published>2016-06-11T17:26:33.000Z</published>
<updated>2019-04-30T13:24:55.895Z</updated>
<content type="html"><![CDATA[<h1 id="一级空间配置器"><a href="#一级空间配置器" class="headerlink" title="一级空间配置器"></a>一级空间配置器</h1><p>当所申请的空间大于128bytes时,stl直接使用一级空间配置器<br>一级空间配置器其实是对malloc的封装,以及添加了类似new_handler处理内存分配不足的情况<br>当内存不足时调用oom_malloc尝试回收一些已分配的内存,调用的是__malloc_alloc_oom_handler方法(如果有的话,没有就抛出异常)</p><a id="more"></a><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="keyword">int</span> inst></span><br><span class="line"><span class="class"><span class="keyword">class</span> __<span class="title">malloc_alloc_template</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> *<span class="title">oom_malloc</span><span class="params">(<span class="keyword">size_t</span> n)</span><span class="comment">//</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">void</span> (*my_malloc_handler) () = <span class="literal">NULL</span>;</span><br><span class="line"><span class="keyword">void</span> *result = <span class="literal">NULL</span>;</span><br><span class="line"><span class="keyword">for</span>(;;)<span class="comment">//不断的去尝试</span></span><br><span class="line">{</span><br><span class="line">my_malloc_handler = __malloc_alloc_oom_handler;</span><br><span class="line"><span class="keyword">if</span>(<span class="literal">NULL</span> == my_malloc_handler)</span><br><span class="line">{</span><br><span class="line">__THROW_BAD_ALLOC;</span><br><span class="line">}<span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">(*my_malloc_handler)();<span class="comment">//调用malloc_handler</span></span><br><span class="line">}</span><br><span class="line">result = <span class="built_in">malloc</span>(n);</span><br><span class="line"><span class="keyword">if</span>(<span class="literal">NULL</span> != result)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">return</span> result;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> *<span class="title">oom_realloc</span><span class="params">(<span class="keyword">void</span> *p,<span class="keyword">size_t</span> n)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">void</span> (*my_malloc_handler) () = <span class="literal">NULL</span>;</span><br><span class="line"><span class="keyword">void</span> *result = <span class="literal">NULL</span>;</span><br><span class="line"><span class="keyword">for</span>(;;)</span><br><span class="line">{</span><br><span class="line">my_malloc_handler = __malloc_alloc_oom_handler;</span><br><span class="line"><span class="keyword">if</span>(<span class="literal">NULL</span> == my_malloc_handler)</span><br><span class="line">{</span><br><span class="line">__THROW_BAD_ALLOC;</span><br><span class="line">}<span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">(*my_malloc_handler)();</span><br><span class="line">}</span><br><span class="line">result = <span class="built_in">realloc</span>(p,n);</span><br><span class="line"><span class="keyword">if</span>(<span class="literal">NULL</span> != result)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">return</span> result;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="title">void</span> <span class="params">(*__malloc_alloc_oom_handler)</span><span class="params">()</span></span>;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> * <span class="title">allocate</span><span class="params">(<span class="keyword">size_t</span> n)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">void</span> * result = <span class="built_in">malloc</span>(n);</span><br><span class="line"><span class="keyword">if</span>(<span class="literal">NULL</span> == result)</span><br><span class="line">{</span><br><span class="line">result = oom_malloc(n);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> result;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">deallocate</span><span class="params">(<span class="keyword">void</span> *p,<span class="keyword">size_t</span><span class="comment">/*n*/</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="built_in">free</span>(p);</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> *<span class="title">reallocate</span><span class="params">(<span class="keyword">void</span> *p,<span class="keyword">size_t</span> <span class="comment">/*old_sz*/</span>,<span class="keyword">size_t</span> new_sz)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">void</span> result = <span class="built_in">realloc</span>(p,new_sz);</span><br><span class="line"><span class="keyword">if</span>(<span class="literal">NULL</span> == result)</span><br><span class="line">{</span><br><span class="line">result = oom_realloc(p,new_sz);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> result;</span><br><span class="line">}</span><br><span class="line"><span class="comment">// set_new_handler ;</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="title">void</span><span class="params">(*set_malloc_handler(<span class="keyword">void</span> (*f)()))</span><span class="params">()</span> <span class="comment">//参数和返回值全是函数指针</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">void</span> (*old)() = __malloc_alloc_oom_handler;</span><br><span class="line">__malloc_alloc_oom_handler = f;</span><br><span class="line"><span class="keyword">return</span> old;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span><<span class="keyword">int</span> inst></span><br><span class="line"><span class="keyword">void</span> (*__malloc_alloc_template<inst>::__malloc_alloc_oom_handler)()= <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> __malloc_alloc_template<<span class="number">0</span>> malloc_alloc;</span><br></pre></td></tr></table></figure><h1 id="二级空间配置器"><a href="#二级空间配置器" class="headerlink" title="二级空间配置器"></a>二级空间配置器</h1><p>二级空间配置器其实是一个内存池,他维持这一个空闲链表数组,所需字节数全上调成8的倍数,然后在空闲链表里面找。<br>当空闲链表内存块不足时,优先从已申请好的空闲堆内存中填充空闲链表<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">enum</span>{__ALIGN = <span class="number">8</span> };</span><br><span class="line"><span class="keyword">enum</span>{__MAX_BYTES = <span class="number">128</span>};</span><br><span class="line"><span class="keyword">enum</span>{__NFREELIST = __MAX_BYTES/__ALIGN};</span><br><span class="line"><span class="keyword">union</span> obj <span class="comment">//链表的结构,空间的有效利用</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">union</span> obj *free_list_link;</span><br><span class="line"><span class="keyword">char</span> client_data[<span class="number">1</span>];</span><br><span class="line">};</span><br><span class="line"><span class="keyword">static</span> obj * <span class="keyword">volatile</span> free_list[__NFREELIST];<span class="comment">//空闲链表数组</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> size_t <span class="title">FREELIST_INDEX</span><span class="params">(<span class="keyword">size_t</span> bytes)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">return</span> (bytes + __ALIGN <span class="number">-1</span>) / __ALIGN <span class="number">-1</span>;<span class="comment">//寻找在数组中的下标位置</span></span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">static</span> size_t <span class="title">ROUND_UP</span><span class="params">(<span class="keyword">size_t</span> bytes)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">return</span> (bytes + __ALIGN <span class="number">-1</span>) & ~(__ALIGN<span class="number">-1</span>);<span class="comment">//上调成8的倍数</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">char</span> * start_free; <span class="comment">//空闲内存起始地址</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">char</span> * end_free; <span class="comment">//空闲内存结束地址</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">size_t</span> heap_size; <span class="comment">//空闲堆内存大小</span></span><br></pre></td></tr></table></figure></p><h2 id="allocate"><a href="#allocate" class="headerlink" title="allocate"></a>allocate</h2><p>如果找到了则把那块空间从free_list中非配给用户,没找到则调用refill()填充free_list<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> * <span class="title">allocate</span><span class="params">(<span class="keyword">size_t</span> n)</span><span class="comment">// 15</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">obj * <span class="keyword">volatile</span> * my_free_list = <span class="literal">NULL</span>;</span><br><span class="line">obj *result = <span class="literal">NULL</span>;</span><br><span class="line"><span class="keyword">if</span>(n > (<span class="keyword">size_t</span>) __MAX_BYTES)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">return</span> malloc_alloc::allocate(n);</span><br><span class="line">}</span><br><span class="line">my_free_list = free_list + FREELIST_INDEX(n);</span><br><span class="line">result = *my_free_list;</span><br><span class="line"><span class="keyword">if</span>(<span class="literal">NULL</span> == result) <span class="comment">//如果free_list为空则调用refill填充或直接分配</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">void</span> *r = refill(ROUND_UP(n));</span><br><span class="line"><span class="keyword">return</span> r;</span><br><span class="line">}</span><br><span class="line">*my_free_list = result->free_list_link;</span><br><span class="line"><span class="keyword">return</span> result;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h2 id="refill"><a href="#refill" class="headerlink" title="refill"></a>refill</h2><p>STL规定refill为内存不足的那块填充20块相应大小的内存块,但是可能出现内存不足的情况所有申请到的不一定是20个内存快(可能只有1个)<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> * <span class="title">refill</span><span class="params">(<span class="keyword">size_t</span> n)</span> <span class="comment">//</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> nobjs = <span class="number">20</span>;</span><br><span class="line"><span class="keyword">char</span> *chunk = chunk_alloc(n,nobjs);<span class="comment">// 申请内存块</span></span><br><span class="line">obj *<span class="keyword">volatile</span>* my_free_list;</span><br><span class="line">obj *result;</span><br><span class="line">obj *current_obj, *next_obj;</span><br><span class="line"><span class="keyword">int</span> i;</span><br><span class="line"><span class="keyword">if</span>(<span class="number">1</span>==nobjs) <span class="keyword">return</span> chunk;</span><br><span class="line">my_free_list=free_list + FREELIST_INDEX(n);</span><br><span class="line">result=(obj *)chunk;</span><br><span class="line">*my_free_list=next_obj=(obj *)(chunk+n);</span><br><span class="line"><span class="keyword">for</span>(i=<span class="number">1</span>;;i++) <span class="comment">//将剩余的块连接到空闲链表</span></span><br><span class="line">{</span><br><span class="line">current_obj = next_obj;</span><br><span class="line">next_obj=(obj *)((<span class="keyword">char</span> *)next_obj + n);</span><br><span class="line"><span class="keyword">if</span>(nobjs <span class="number">-1</span>==i)</span><br><span class="line">{</span><br><span class="line">current_obj->free_list_link=<span class="number">0</span>;</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line">current_obj->free_list_link=next_obj;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> result; <span class="comment">//将第一个内存块返回</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h2 id="chunk-alloc"><a href="#chunk-alloc" class="headerlink" title="chunk_alloc"></a>chunk_alloc</h2><p>chunk_alloc函数分配内存块给free_list,他和refill是维持这个结构的核心。处理了多种内存不足的情况<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">char</span> * <span class="title">chunk_alloc</span><span class="params">(<span class="keyword">size_t</span> size,<span class="keyword">int</span> &nobjs)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">char</span> *result = <span class="literal">NULL</span>;</span><br><span class="line"><span class="keyword">size_t</span> total_bytes = size*nobjs;</span><br><span class="line"><span class="keyword">size_t</span> bytes_left = end_free - start_free;</span><br><span class="line"><span class="keyword">if</span>(bytes_left >= total_bytes)<span class="comment">//当剩余内存完全足够</span></span><br><span class="line">{</span><br><span class="line">result = start_free;</span><br><span class="line">start_free += total_bytes;</span><br><span class="line"><span class="keyword">return</span> result;</span><br><span class="line">}<span class="keyword">else</span> <span class="keyword">if</span>(bytes_left >= size)<span class="comment">//内存不够分配20块但能分配一块或一块以上</span></span><br><span class="line">{</span><br><span class="line">nobjs = bytes_left/size;</span><br><span class="line">total_bytes = size*nobjs;</span><br><span class="line">result = start_free;</span><br><span class="line">start_free += total_bytes;</span><br><span class="line"><span class="keyword">return</span> result;</span><br><span class="line">}<span class="keyword">else</span> <span class="comment">//剩余内存一块都不能分配</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">size_t</span> bytes_to_get=<span class="number">2</span> *total_bytes+ROUND_UP(heap_size>><span class="number">4</span>);</span><br><span class="line"><span class="comment">//先给剩余的内存找到合适的free list(先处理start_free——end_free的那段内存)</span></span><br><span class="line"><span class="keyword">if</span>(bytes_left><span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line">obj * <span class="keyword">volatile</span> *my_free_list=free_list +FREELIST_INDEX(bytes_left);</span><br><span class="line">((obj *)start_free)->free_list_link= *my_free_list;</span><br><span class="line">*my_free_list=(obj *)start_free;</span><br><span class="line">}</span><br><span class="line"><span class="comment">//向堆空间申请内存</span></span><br><span class="line">start_free=(<span class="keyword">char</span> *)<span class="built_in">malloc</span>(bytes_to_get);</span><br><span class="line"><span class="keyword">if</span>(<span class="number">0</span>==start_free)<span class="comment">//堆空间不足时</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">int</span> i;</span><br><span class="line">obj *<span class="keyword">volatile</span>* my_free_list,*p;</span><br><span class="line"><span class="comment">//遍历比他大的free list查看是否还剩有未使用内存</span></span><br><span class="line"><span class="keyword">for</span>(i=size;i<__MAX_BYTES;i+=__ALIGN)</span><br><span class="line">{</span><br><span class="line">my_free_list = free_list +FREELIST_INDEX(i);</span><br><span class="line">p = *my_free_list;</span><br><span class="line"><span class="keyword">if</span>(<span class="number">0</span>!=p)<span class="comment">//</span></span><br><span class="line">{</span><br><span class="line">*my_free_list = p ->free_list_link;</span><br><span class="line">start _free = (<span class="keyword">char</span> *)p;</span><br><span class="line">end_free = (<span class="keyword">char</span> *)p;</span><br><span class="line"><span class="comment">//由于nobjs 传的是引用所以递归调用修正nobjs</span></span><br><span class="line"><span class="keyword">return</span> (chunk_alloc(size,nobjs));</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">end_free=<span class="number">0</span>;</span><br><span class="line"><span class="comment">//调用一级空间配置器,看看malloc_handler能否挤出内存...</span></span><br><span class="line">start_free =(<span class="keyword">char</span> *)malloc_alloc::allocate(bytes_to_get);</span><br><span class="line">}</span><br><span class="line">heap_size +=bytes_to_get;</span><br><span class="line">end_free =start_free +bytes_to_get;</span><br><span class="line"><span class="keyword">return</span> (chunk_alloc(size,nobjs));<span class="comment">//同上</span></span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h2 id="释放内存"><a href="#释放内存" class="headerlink" title="释放内存"></a>释放内存</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">deallocate</span><span class="params">(<span class="keyword">void</span> *p,<span class="keyword">size_t</span> n)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">obj * <span class="keyword">volatile</span> * my_free_list = <span class="literal">NULL</span>;</span><br><span class="line">obj *q = (obj*)p;</span><br><span class="line"><span class="keyword">if</span>(n > (<span class="keyword">size_t</span>) __MAX_BYTES)</span><br><span class="line">{</span><br><span class="line">malloc_alloc::deallocate(p,n);</span><br><span class="line"><span class="keyword">return</span> ;</span><br><span class="line">}</span><br><span class="line">my_free_list = free_list + FREELIST_INDEX(n);</span><br><span class="line">q->free_list_link = *my_free_list;</span><br><span class="line">*my_free_list = q;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="结构图"><a href="#结构图" class="headerlink" title="结构图"></a>结构图</h1><p>如图:<br><img src="/imgs/Summary/stl_alloc.png" alt="二级空间配置器内存结构"><br>参考资料——STL源码剖析</p>]]></content>
<summary type="html">
<h1 id="一级空间配置器"><a href="#一级空间配置器" class="headerlink" title="一级空间配置器"></a>一级空间配置器</h1><p>当所申请的空间大于128bytes时,stl直接使用一级空间配置器<br>一级空间配置器其实是对malloc的封装,以及添加了类似new_handler处理内存分配不足的情况<br>当内存不足时调用oom_malloc尝试回收一些已分配的内存,调用的是__malloc_alloc_oom_handler方法(如果有的话,没有就抛出异常)</p>
</summary>
<category term="Summary" scheme="http://yoursite.com/categories/Summary/"/>
<category term="C++" scheme="http://yoursite.com/tags/C/"/>
<category term="STL" scheme="http://yoursite.com/tags/STL/"/>
<category term="alloc" scheme="http://yoursite.com/tags/alloc/"/>
</entry>
<entry>
<title>海量数据中求最大的K个数</title>
<link href="http://yoursite.com/2016/06/06/heap_sort/"/>
<id>http://yoursite.com/2016/06/06/heap_sort/</id>
<published>2016-06-06T04:18:38.000Z</published>
<updated>2019-04-30T13:24:27.157Z</updated>
<content type="html"><![CDATA[<h1 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h1><p>在n个数中求最大的K个数</p><h1 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h1><p>建立一个K个节点的小根堆,再遍历n个数<br>与小根堆的第一个元素比较</p><h1 id="code"><a href="#code" class="headerlink" title="code"></a>code</h1><a id="more"></a><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line">#include<iostream></span><br><span class="line">#include<cstdlib></span><br><span class="line">using namespace std;</span><br><span class="line"></span><br><span class="line">void heap_adjust(int *arr, int start, int end)</span><br><span class="line">{</span><br><span class="line">int tmp = arr[start];</span><br><span class="line">for (int i = 2 * start + 1; i <= end; i = i * 2 + 1)</span><br><span class="line">{</span><br><span class="line">if (i + 1 <= end && arr[i]>arr[i + 1])</span><br><span class="line">{</span><br><span class="line">i++;</span><br><span class="line">}</span><br><span class="line">if (tmp > arr[i])</span><br><span class="line">{</span><br><span class="line">arr[start] = arr[i];</span><br><span class="line">start = i;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">arr[start] = tmp;</span><br><span class="line">}</span><br><span class="line">void heap_sort(int *arr, int length)</span><br><span class="line">{</span><br><span class="line">//调整成小根堆</span><br><span class="line">for (int i = (length - 1 - 1) / 2; i >= 0; i--)</span><br><span class="line">{</span><br><span class="line">heap_adjust(arr, i, length - 1);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">int * find_max_N(int *arr, int len,int n)</span><br><span class="line">{</span><br><span class="line">if (arr == NULL || len < n||n<1)return NULL;</span><br><span class="line">int *brr = new int[n];//先让brr为arr的前n个</span><br><span class="line">memcpy(brr, arr, sizeof(int)* n);</span><br><span class="line">heap_sort(brr, n);//把前n个调整为小根堆</span><br><span class="line">for (int i = n; i < len; ++i)</span><br><span class="line">{</span><br><span class="line">if (arr[i]>brr[0])//如果有值比brr[0]大,则进行赋值后再次调整</span><br><span class="line">{</span><br><span class="line">brr[0] = arr[i];</span><br><span class="line">heap_adjust(brr, 0, n-1);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">return brr;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>利用堆排序的思想,时间复杂度为O(n*logk),空间复杂度为O(K)</p><h1 id="其他解法"><a href="#其他解法" class="headerlink" title="其他解法"></a>其他解法</h1><p>使用快速排序划分的做法</p>]]></content>
<summary type="html">
<h1 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h1><p>在n个数中求最大的K个数</p>
<h1 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h1><p>建立一个K个节点的小根堆,再遍历n个数<br>与小根堆的第一个元素比较</p>
<h1 id="code"><a href="#code" class="headerlink" title="code"></a>code</h1>
</summary>
<category term="Algorithm" scheme="http://yoursite.com/categories/Algorithm/"/>
<category term="C++" scheme="http://yoursite.com/tags/C/"/>
</entry>
</feed>