﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-Amazing110</title><link>http://www.cppblog.com/Amazing110/</link><description /><language>zh-cn</language><lastBuildDate>Tue, 14 Apr 2026 23:06:16 GMT</lastBuildDate><pubDate>Tue, 14 Apr 2026 23:06:16 GMT</pubDate><ttl>60</ttl><item><title>配接器、萃取器、分配器、迭代器--STL的精髓</title><link>http://www.cppblog.com/Amazing110/archive/2011/11/01/159427.html</link><dc:creator>天人雨</dc:creator><author>天人雨</author><pubDate>Tue, 01 Nov 2011 02:04:00 GMT</pubDate><guid>http://www.cppblog.com/Amazing110/archive/2011/11/01/159427.html</guid><wfw:comment>http://www.cppblog.com/Amazing110/comments/159427.html</wfw:comment><comments>http://www.cppblog.com/Amazing110/archive/2011/11/01/159427.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Amazing110/comments/commentRss/159427.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Amazing110/services/trackbacks/159427.html</trackback:ping><description><![CDATA[<span style="font-size: 12pt">今天重读《STL源码分析》，一目十行，看的很爽，想起当年看这本书，看着脑袋就大。说明这些年，功力还是有所增长的。</span><br /><span style="font-size: 12pt">STL的精髓，总结起来，就四点：配接器（包括仿函数），萃取器、分配器、迭代器。其中分配器和迭代器是常人能想出的产物，萃取器是高手想出的产物，配接器是大师想出的产物。</span><br /><br /><span style="font-size: 12pt">分配器需要记住的是，一般的内存分配器没有启用次级分配能力，只启用了一级分配器，即直接使用malloc和free来分配释放内存，STL为了提高效率，将分配内存和调用构造函数分开，为的是节省某些不需要调用构造函数的开销。次级分配能力在启用后，会根据分配内存的大小来决定是否使用内存池。</span><br /><br /><span style="font-size: 12pt">迭代器需要注意的地方，只有在其中使用的萃取器，这个萃取器的设计还是比较神妙的，迭代器作为一个类，在泛型算法中，怎样让编译器推导出返回值？普通的做法是使用typedef，但直接将迭代器传入的类型做typedef并不能解决泛型算法对裸指针的兼容。于是，萃取器出现了。</span><br /><span style="font-size: 12pt">
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #000000">template&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;T</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">struct</span><span style="color: #000000">&nbsp;iterator_trait<br /><img id="Codehighlighter1_41_65_Open_Image" onclick="this.style.display='none'; Codehighlighter1_41_65_Open_Text.style.display='none'; Codehighlighter1_41_65_Closed_Image.style.display='inline'; Codehighlighter1_41_65_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_41_65_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_41_65_Closed_Text.style.display='none'; Codehighlighter1_41_65_Open_Image.style.display='inline'; Codehighlighter1_41_65_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_41_65_Closed_Text"><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_41_65_Open_Text"><span style="color: #000000">{<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />typedef&nbsp;T&nbsp;value_type;<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif"  alt="" />}</span></span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />template&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;I</span><span style="color: #000000">*&gt;</span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">struct</span><span style="color: #000000">&nbsp;iterator_trait<br /><img id="Codehighlighter1_110_134_Open_Image" onclick="this.style.display='none'; Codehighlighter1_110_134_Open_Text.style.display='none'; Codehighlighter1_110_134_Closed_Image.style.display='inline'; Codehighlighter1_110_134_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_110_134_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_110_134_Closed_Text.style.display='none'; Codehighlighter1_110_134_Open_Image.style.display='inline'; Codehighlighter1_110_134_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_110_134_Closed_Text"><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_110_134_Open_Text"><span style="color: #000000">{<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />typedef&nbsp;I&nbsp;value_type;<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif"  alt="" />}</span></span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span></div>这样无论是真正的Iterator还是int*，获取的value_type都是真正的对象类型。（还需要对const int*进行萃取）。</span><br /><span style="font-size: 12pt">萃取器在迭代器中的神妙使用，使其在其他地方也被使用，打个比方，有的类需要调用构造函数，有的类不需要调用。如果让我等菜鸟去设计，肯定逃不过if-else或者虚函数。但是STL使用了一种更为高效、优雅的解决方案。</span><br /><span style="font-size: 12pt">首先，定义两个空类，true_type,false_type;</span><br /><span style="font-size: 12pt">然后，定义萃取器：</span><br /><span style="font-size: 12pt">template &lt;class T&gt;</span><br /><span style="font-size: 12pt">struct __type_trait</span><br /><span style="font-size: 12pt">{</span><br /><span style="font-size: 12pt">typedef true_type need_construct;//默认时所有类都需要调用构造函数</span><br /><span style="font-size: 12pt">}</span><br /><span style="font-size: 12pt">假设int不需要调用构造函数，则对模板进行特化：</span><br /><span style="font-size: 12pt">template &lt;int&gt;</span><br /><span style="font-size: 12pt">struct __type_trait</span><br /><span style="font-size: 12pt">{</span><br /><span style="font-size: 12pt">typedef false_type need_construct;</span><br /><span style="font-size: 12pt">}</span><br /><span style="font-size: 12pt">然后，定义两个重载的函数：</span><br /><span style="font-size: 12pt">void func( true_type ); //这个函数里面会调用构造函数</span><br /><span style="font-size: 12pt">void func( false_type ); //这个函数里面不会调用构造函数</span><br /><span style="font-size: 12pt">最后，调用func时这么调用：</span><br /><span style="font-size: 12pt">func( __type_trait&lt;T&gt;::need_construct );</span><br /><span style="font-size: 12pt">OK，这里没有分支，没有虚函数，最高效。这就是元编程的威力，实际上，编译器就为我们提供了重载的能力！</span><br /><br /><span style="font-size: 12pt">对迭代器来说，其中有五种型别，是需要萃取实现的，他们分别是：</span><br /><span style="font-size: 12pt">1，value_type：表示该迭代器指向的是什么类型</span><br /><span style="font-size: 12pt">2，different_type：表示迭代器之间的距离是什么型别的，一般是int</span><br /><span style="font-size: 12pt">3，pointer_type：指针类型，表示value_type的指针类型是啥</span><br /><span style="font-size: 12pt">4，reference_type：引用类型，表示value_type的引用类型是啥。</span><br /><span style="font-size: 12pt">5，iterator_category：表示该iterator是一个什么类型，是双向的？还是单向的？还是随机的？</span><br /><span style="font-size: 12pt">这些类型都是要通过萃取得来的，否则无法兼容裸指针</span><br /><span style="font-size: 12pt">此外，还有size_type之类的型别。反向的迭代器，其实是一个配接器，怎么配结的呢，反向迭代器也是一个模板类，这个模板类在获得T之后，就获得了真正对象的控制权，于是做出如何的行为就都可以实现了。</span><br /><br /><span style="font-size: 12pt">分配器是最神妙的东西，如果不去仔细阅读代码，分配器简直可以用巧夺天工来形容，但读了代码之后，才发现其中奥妙。</span><br /><span style="font-size: 12pt">说到分配器，就不能不谈仿函数，仿函数就是利用对象的（）重载，来实现函数的功能，STL只支持一元仿函数和二元仿函数。注意，这点很重要，多元的仿函数，会让制作配接器的人很烦。配接器是怎么做的呢？配接器的原理就是，配接器也是一个类，这个类在构造的时候，传入仿函数的对象，这样，配接器内部就可以将仿函数对象作为成员记载下来，等（）去执行的时候，再去使用成员去调用仿函数。由于类里面可以有多个成员，这样，就可以将多个仿函数进行组合后一起调用，实现一些很神奇的功能。</span><br /><span style="font-size: 12pt">为什么STL里面的泛型算法全部是仿函数？就是因为只有仿函数，才能让配接器实现，如果使用函数，配接器是无法实现的，因为配接器是类，类里面即使保存函数的指针，可以实现一次配接，但配接之后就不能再配接了。而使用仿函数的话，由于配接器也是对象，配接之后还可以再配接，形成自由组合，循环，神妙得多。如果配接器不使用类，那么配接时要存储的仿函数或者函数指针就没地方放，全局变量是没有域限制的。</span><br /><span style="font-size: 12pt">仿函数如果要支持被配接，就必须继承unary_function类（一元）或者binary_function类（二元），这里面定义了返回值和参数的性别，这使得构造配接器时，就可以直接使用这些性别来进行配结。</span><span class="Apple-converted-space">&nbsp;</span><br /><span style="font-size: 12pt">构建完配接器这么强大的体系之后，STL再提供了将普通函数配接为仿函数的配接器，提供了将成员函数配接为仿函数的配接器，这样，普通函数和成员函数也可被配接器配成仿函数之后再进行配结，从而实现了程序过程的完全自由组合。</span><img src ="http://www.cppblog.com/Amazing110/aggbug/159427.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Amazing110/" target="_blank">天人雨</a> 2011-11-01 10:04 <a href="http://www.cppblog.com/Amazing110/archive/2011/11/01/159427.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>智能指针</title><link>http://www.cppblog.com/Amazing110/archive/2011/09/30/157219.html</link><dc:creator>天人雨</dc:creator><author>天人雨</author><pubDate>Fri, 30 Sep 2011 04:16:00 GMT</pubDate><guid>http://www.cppblog.com/Amazing110/archive/2011/09/30/157219.html</guid><wfw:comment>http://www.cppblog.com/Amazing110/comments/157219.html</wfw:comment><comments>http://www.cppblog.com/Amazing110/archive/2011/09/30/157219.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Amazing110/comments/commentRss/157219.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Amazing110/services/trackbacks/157219.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->#include&nbsp;&lt;iostream&gt;using&nbsp;namespace&nbsp;std;template&nbsp;&lt;class&nbsp;T&gt;class&nb...&nbsp;&nbsp;<a href='http://www.cppblog.com/Amazing110/archive/2011/09/30/157219.html'>阅读全文</a><img src ="http://www.cppblog.com/Amazing110/aggbug/157219.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Amazing110/" target="_blank">天人雨</a> 2011-09-30 12:16 <a href="http://www.cppblog.com/Amazing110/archive/2011/09/30/157219.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>