﻿<?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++博客-xiaoguozi's Blog-随笔分类-C++</title><link>http://www.cppblog.com/guojingjia2006/category/14893.html</link><description>Pay it forword - 我并不觉的自豪，我所尝试的事情都失败了······习惯原本生活的人不容易改变，就算现状很糟，他们也很难改变，在过程中，他们还是放弃了······他们一放弃，大家就都是输家······让爱传出去，很困难，也无法预料，人们需要更细心的观察别人，要随时注意才能保护别人，因为他们未必知道自己要什么·····</description><language>zh-cn</language><lastBuildDate>Fri, 11 Jan 2013 11:21:12 GMT</lastBuildDate><pubDate>Fri, 11 Jan 2013 11:21:12 GMT</pubDate><ttl>60</ttl><item><title>Centos编译boost</title><link>http://www.cppblog.com/guojingjia2006/archive/2013/01/07/197075.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Mon, 07 Jan 2013 08:38:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2013/01/07/197075.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/197075.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2013/01/07/197075.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/197075.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/197075.html</trackback:ping><description><![CDATA[<div>http://blog.sina.com.cn/s/blog_6f2caee40100uhj6.html</div><div><div id="sina_keyword_ad_area2"  "=""> 			<div>1.下载最新的boost</div> <div>http://www.boost.org/</div> <div></div> <div>2.解压文件</div> <div>tar -xzvf boost_1_45_0.tar.gz&nbsp;<wbr></div> <div></div> <div>3.编译bjam</div> <div>进入boost_1_45_0目录中，运行./bootstrap.sh，完成后会得到一个bjam</div> <div></div> <div>4.编译boost&nbsp;<wbr></div> <div>./bjam --with-date_time --with-system --with-regex --with-thread --with-filesystem --with-serialization --with-iostreams --with-math --with-mpi --with-program_options --with-python --with-math --with-signals --layout=tagged install variant=debug,release link=static --runtime-link=static threading=multi stage</div> <div></div> <div>5.查看boost</div> <div> 编译完成后，在/usr/local/include/boost就有最新的boost头文件了，在/usr/local/lib就有编译好的.a库文件了。</div> <div> 虽然usr/local/include和/usr/include都有目录，但GCC是先访问/usr/local/include，所以编译完成后，就可以默认使用boost了。</div> <div></div> <div>6.测试boost</div> <div>vi testboost.cpp</div> <div></div> <div>#include &lt;iostream&gt;</div> <div>#include &lt;boost/version.hpp&gt;</div> <div></div> <div>int main()</div> <div>{</div> <div>&nbsp;<wbr> &nbsp;<wbr> std::cout&lt;&lt;BOOST_VERSION&lt;&lt;std::endl;</div> <div>&nbsp;<wbr> &nbsp;<wbr> return 0;</div> <div>}</div> <div></div> <div></div> <div>编译:g++ -o testboost testboost.cpp</div>							 		</div></div><img src ="http://www.cppblog.com/guojingjia2006/aggbug/197075.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2013-01-07 16:38 <a href="http://www.cppblog.com/guojingjia2006/archive/2013/01/07/197075.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>mint 下codeblocks 编译libapue </title><link>http://www.cppblog.com/guojingjia2006/archive/2013/01/04/196955.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Fri, 04 Jan 2013 12:23:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2013/01/04/196955.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/196955.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2013/01/04/196955.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/196955.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/196955.html</trackback:ping><description><![CDATA[codeblocks很轻巧也很好用对于c/c++编写在linux下相对于eclipse.<br />于是乎下了一个，由于是乎想写几个sample玩玩。于是乎拿&lt;unix 高级环境编程&gt; sample来测试。<br /><br />于是乎建了一个c++ project. <div>&lt;unix 高级环境编程&gt;里的例子有个apue.h头文件。不是系统自带的。是作者自己写的几个util函数。<br />网上找编译apue.h头文件一大片。但是都是考来考去，不过核心的都差不多。不过有个方法是编译完<br />libapue.a静态库后，还需要在apute.h头文件尾巴加"error.c"。。完了拷贝error.c实现到目录。。<br />看完后。我惊了呆。。好吧。。这库还能这么用。。<br /><br />既然libapue.a编译完后，apue.h里的函数声明在libapue.a都已经实现，当然包括err_xxx系列的。所以<br />在apue.h加"error.c"是画蛇添足。。这里不推荐此方法。。<br /><br />我的环境是mint14下, IDE用的是 codeblocks. 方法中基本都有这么一个步骤：<br /><div> <div>先在这个网站&nbsp;http://www.apuebook.com/src.tar.gz  下载tar.gz格式的源码包，然后解压至某个目录，比如说/home/xiaoguozi/下，然后进入目录apue.2e，把文件  Make.defines.linux 中的 WKDIR=/home/xxx/apue.2e 修改为  WKDIR=/home/xiaoguozi/apue.2e  ，然后再进入apue.2e目录下的std目录，打开linux.mk，将里面的nawk全部替换为awk</div></div>如果用vim编辑的话，可以用 :1,%s/nawk/awk/g 替换字符窜<br /><br />完了make, 过程中，还遇到了几个问题。(mint下,其他os不太清楚)<br /><div><p><span style="font-size:18px">1: /usr/include/bits/timex.h:31:7:error: expect ':' , ',' , ';' , '}' or '__attribute__'&nbsp; &nbsp; <br /></span><span style="font-size:18px">&nbsp;apue.2e/ipp/ipp.h中 #define status u.st 与 timex.h中的 status 冲突，更改 #define Status u.st</span></p> <p><span style="font-family:Arial; line-height:26px"><span style="font-size:14px">&nbsp;&nbsp;</span></span></p> <p><span style="font-family:Arial; line-height:26px"><span style="font-size:14px"><span style="margin:0px; padding:0px; border:none; font-family:Consolas,'Courier New',Courier,mono,serif; line-height:17.600000381469727px">2：ARG_MAX 未定义</span></span></span></p> <p><span style="font-family:Consolas,Courier New,Courier,mono,serif; font-size:14px"><span style="line-height:17.600000381469727px">&nbsp; &nbsp;在include/apue.h中加入 #define ARG_MAX 4096</span></span></p> <p><span style="font-family:Consolas,Courier New,Courier,mono,serif; font-size:14px"><span style="line-height:17.600000381469727px">&nbsp; &nbsp;在threadctl/getenv1.c 加入 #include "../include/apue.h"</span></span></p> <p><span style="font-family:Consolas,Courier New,Courier,mono,serif; font-size:14px"><span style="line-height:17.600000381469727px">&nbsp; &nbsp;在threadctl/getenv3.c 加入 #include "../include/apue.h"</span></span></p></div>完了之后，make应该就可以成功了<br /><br />完了在codeblocks项目里引用刚编译完的库，有几个方法:<br />1)将编译完的库,头文件apue.h拷贝/usr/include,库文件libapue.a拷贝到/usr/lib下，这个是系统目录，gcc编译的时候会在这目录搜寻<br />2)在项目属性添加静态库引用<br /><div>添加头文件：依次点击project-&gt;bulid options-&gt;Search directories，在该标签页中点击Compiler，单击Add按钮添加头文件路径<br />添加静态库路径：依次点击project-&gt;bulid options-&gt;Linker setting，在该标签页中点击Add按钮添加静态库路径。<br /><br />如果之前你建的是c project的话，应该就可以顺利编译通过了，但是对于建立c++的project,仍然提示链接错误，找不到函数实现，<br />原因是libapue.a是c库，用g++编译的时候要引用c库的话，因为c++编译的时候会在函数加一些额外字符，所以当然会链接错误。</div><div>解决也简单的在函数库前加 extern "C",或者直接把apue.h用extern "C"包含，不清楚的补下相应知识。<br /><br />加点额外的知识关于gcc/g++：<br /><div>gcc和g++的区别<p>误区一:gcc只能编译c代码,g++只能编译c++代码<br />两者都可以，但是请注意：<br />1.后缀为.c的，gcc把它当作是C程序，而g++当作是c++程序；后缀为.cpp的，两者都会认为是c++程序，注意，虽然c++是c的超集，但是两者对语法的要求是有区别的。C++的语法规则更加严谨一些。<br />2.编译阶段，g++会调用gcc，对于c++代码，两者是等价的，但是因为gcc命令不能自动和C＋＋程序使用的库联接，所以通常用g++来完成链接，为了统一起见，干脆编译/链接统统用g++了，这就给人一种错觉，好像cpp程序只能用g++似的。<br /><br />误区二:gcc不会定义__cplusplus宏，而g++会<br />实际上，这个宏只是标志着编译器将会把代码按C还是C++语法来解释，如上所述，如果后缀为.c，并且采用gcc编译器，则该宏就是未定义的，否则，就是已定义。<br /><br />误区三:编译只能用gcc，链接只能用g++<br />严格来说，这句话不算错误，但是它混淆了概念，应该这样说：编译可以用gcc/g++，而链接可以用g++或者gcc -lstdc++。因为gcc命令不能自动和C＋＋程序使用的库联接，所以通常使用g++来完成联接。但在编译阶段，g++会自动调用gcc，二者等价。</p>                                                                                                                          gcc和g++的区别                                                                                                                                                                                                                                                                                                                                                                       我们在编译c/c++代码的时候，有人用gcc，有人用g++，于是各种说法都来了，譬如c代码用gcc，而c++代码用g++，或者说编译用  gcc，链接用g++，一时也不知哪个说法正确，如果再遇上个extern  "C"，分歧就更多了，这里我想作个了结，毕竟知识的目的是令人更清醒，而不是更糊涂。</div></div><br /></div><img src ="http://www.cppblog.com/guojingjia2006/aggbug/196955.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2013-01-04 20:23 <a href="http://www.cppblog.com/guojingjia2006/archive/2013/01/04/196955.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Installing Gearman and gearmand on Windows with Cygwin </title><link>http://www.cppblog.com/guojingjia2006/archive/2012/12/28/196743.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Fri, 28 Dec 2012 03:17:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2012/12/28/196743.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/196743.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2012/12/28/196743.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/196743.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/196743.html</trackback:ping><description><![CDATA[<div><p>Recently I've come face-to-face with a significant processing task  for a web application written in PHP.&nbsp; I haven't worked with process  control very much, so I started researching ways of distributing the  calculations to multiple processes.&nbsp; PHP offers several libraries for  doing this (<a href="http://php.net/pcntl">pcntl</a>, <a href="http://php.net/posix">POSIX</a>),  but it quickly became clear that if you're running Windows these  libraries are not an option, and unfortunately at work I have a Windows  machine.&nbsp; After a lot more research, I came across <a href="http://gearman.org">Gearman</a>.</p> <p>Gearman is essentially a distributed processing framework, and seems  to have community support for many programming languages.&nbsp; It consists  of two main components: the job server, and a Client and Worker API.&nbsp;  The Client and Worker API can be used in a wide variety of languages,  but the job server is only available as a C library or a Perl library.&nbsp;  This makes it a bit tougher to get the server running on Windows,  especially when you start running into some of the dependencies that it  requires to build.&nbsp; As well, the Client/Worker API for PHP can only be  installed as a PECL extension, or a very-out-of-date PEAR extension  called Net_Gearman.</p> <p>Nonetheless, after yet more research I decided that I would give it a shot by using <a href="http://www.cygwin.com">Cygwin</a>  to get the job server running (if you haven't used Cygwin before, be  sure to read about it before attempting to install Gearman this way),  and PEAR to use the API.&nbsp; Pre-built PECL extensions aren't available for  Windows anymore, and the  build process for PHP extensions can be  pretty painful, so it makes PEAR  look good by comparison even if the  code will be out of date.</p> <p>I had a pretty frustrating time finally getting everything up and  running due to various dependency issues, so I went back through the  whole process and wrote it out step-by-step.&nbsp; I used a Windows XP SP3  machine for this, but I also got it working on a Windows 7 machine as  well.</p> <h2>Installing the Gearman job server (gearmand) on Windows with Cygwin</h2> <h4>Installing Cygwin</h4> <ol><li>If you don't have Cygwin already, you can get it from <a href="http://www.cygwin.com/">http://www.cygwin.com</a>.&nbsp; The setup file is located <a href="http://cygwin.com/setup.exe">here</a>,  and the setup process is pretty straightforward; run it and follow the  wizard.&nbsp; Full installation instructions are available at the Cygwin  site.</li><li>Keep the Cygwin setup.exe file handy after you've installed the  default software packages, as you'll need it in the future to add  packages, similar to apt-get, yum, and other Linux/UNIX package  managers.</li><li>Cygwin installs with some basic packages, including a Cygwin Bash  Shell that goes into your Start Menu.&nbsp; I prefer the mintty emulator  instead, as it has less of a DOS Command Prompt feel and better terminal  features.&nbsp; Feel free to use whatever shell you like of course.&nbsp; You can  get mintty by re-running the setup.exe, and at the package selection  screen, type 'mintty' into the Search bar at the top left.&nbsp; Expand the  "Shells" category, and click on the word "Skip" under the "New" column  beside the mintty package to select it before continuing the install  process.</li></ol> <h4>Installing Cygwin Package Dependencies needed for Gearman</h4> <p>If you're not already in the Cygwin setup, re-run the Cygwin  setup.exe and go through to the package selection screen.&nbsp; The following  is a list of dependency packages you will need in order to build the  Gearman job server (gearmand).&nbsp; None of these packages were installed by  default with Cygwin:</p> <ul><li>gcc</li><li> make</li><li> libuuid1-devel</li><li> libiconv</li></ul> <p>There's a good <a href="http://www.eecg.utoronto.ca/%7Eaamodt/ece242/cygwin.html">installation tutorial here</a>  that walks through getting gcc and make installed for people unfamiliar  with Cygwin.&nbsp; Finding the others is pretty straightforward, the Search  bar in the package selector works well.</p> <h4>Installing libevent</h4> <p>Gearmand requires an event notification library called <a href="http://monkey.org/%7Eprovos/libevent/">libevent </a>that you cannot get as a Cygwin package, which means it has to be installed from source.&nbsp; You can get the source <a href="http://monkey.org/%7Eprovos/libevent/">here</a>.</p> <ol><li>Download and unpack the latest <a href="http://monkey.org/%7Eprovos/libevent/">libevent </a>stable release.&nbsp; At the time of this writing, I used libevent-1.4.14b-stable.<br /> <em><strong>NOTE</strong></em>: Download and unpack to a <strong>directory that does not contain spaces in the name</strong>,  such as "C:/cygwin/home/Zombat/libevent-1.4.14b-stable".&nbsp; If you unpack  to something with spaces like "C:/Documents and Settings/Zombat/", the  build process might not be able to install libevent correctly (libtool  has a hard time with spaces)!</li><li>Open a Cygwin shell and <code>cd</code> to the unpacked libevent directory.</li><li>Run the following commands:</li></ol> <p style="padding-left: 60px;"><code>./configure<br /> make<br /> make install</code></p> <p>libevent should now be installed and ready to be used when compiling the Gearman job server.</p> <h4>Installing the Gearman job server, gearmand.exe</h4> <ol><li>Download and unpack the C implementation of gearmand from http://gearman.org/index.php?id=download</li><li>Open a cygwin shell and cd to your unpacked gearmand directory.&nbsp;  Same rules apply as before, make sure you've unpacked in a directory  with no spaces in the path!&nbsp; libtool hates that, and your build may  fail.</li><li>Run the following commands:</li></ol> <p style="padding-left: 60px;"><code>./configure<br /> make<br /> make install</code></p> <p>The Gearman job server should now be installed and ready to use!&nbsp;  Mine was installed at /usr/local/sbin/gearmand.exe, and running it with a  "triple verbose" flag (<code>-vvv</code>) should produce the following:</p> <p><a href="http://www.phpvs.net/wp-content/uploads/2010/10/gearmand-output.png"><img wp-image-248=""  aligncenter"="" title="gearmand-output" src="http://www.phpvs.net/wp-content/uploads/2010/10/gearmand-output.png" alt="gearmand.exe startup debug output" height="144" width="355" /></a></p> <p>That's it for the job server.&nbsp; When you want to start it, simply open a Cygwin shell and run <code>gearmand.exe</code>.&nbsp;  Running it with the -d flag will cause the server to run as a daemon in  the background, and running with --help will show you the full option  list.</p> <h3>Installing the Gearman Client and Worker API (Net_Gearman)<strong><br /> </strong></h3> <p>I chose to install the PEAR Client and  Worker API, as it is native PHP and doesn't involve compiling PECL  extensions.&nbsp; The PEAR package is called Net_Gearman, and was originally  written by Joe Stump at Digg.com.&nbsp; It is old and out of date now,  although there appears to be a more recent fork at  http://github.com/brianlmoon/net_gearman.&nbsp; I stuck with the older  version, as I suspect it will meet my needs, and was readily available  as a PEAR package.</p> <p>This also makes installation relatively  painless.&nbsp; Assuming you've previously set PEAR up, then all you have to  do is open a command window (not a Cygwin shell) and run:</p> <blockquote> <p><code>pear install Net_Gearman-alpha</code></p> </blockquote> <p>The "-alpha" portion is necessary, as  Net_Gearman apparently never made it to a stable release version.&nbsp; That  being said, it has functioned well for me so far.&nbsp; Perhaps someone will  pick the project up in the future.</p> <p>I'll write more about getting started with  the Client and Worker API in the next article, so we can actually use  Gearman to get some work done.</p></div>转自:<div>http://www.phpvs.net/2010/11/30/installing-gearman-and-gearmand-on-windows-with-cygwin/</div><img src ="http://www.cppblog.com/guojingjia2006/aggbug/196743.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2012-12-28 11:17 <a href="http://www.cppblog.com/guojingjia2006/archive/2012/12/28/196743.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>aio,epoll,libevent,boost::asio解决的问题</title><link>http://www.cppblog.com/guojingjia2006/archive/2012/11/09/194979.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Fri, 09 Nov 2012 07:56:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2012/11/09/194979.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/194979.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2012/11/09/194979.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/194979.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/194979.html</trackback:ping><description><![CDATA[<div> 		aio是linux2.6以后内核实现的异步IO，或者说他才是真正意义上的异步IO。<br /> epoll作为select的linux的替代品，解决了selectfd_set的限制。性能优于select。而在max平台上替代方案是kqueue。<br /> libevent是一个跨平台异步解决方案，他根据不同的平台提供了不同的异步方案，采用Reactor模型实现。<br /> Boost::asio是一个跨平台的网络及底层IO的C++<a href="http://www.2cto.com/kf" target="_blank">编程</a>库，实现了对TCP、UDP、ICMP、串口的支持。对于读写方式，ASIO支持同步和异步两种方式。采用了epoll来实现，插入了大量的信号处理。Asio库不需要单独便于，但是测试过程中对boost::system的依赖可能会需要编译部分boost中的库。<br /> muduo采用Reactor模型实现的网络库，只支持<a href="http://www.2cto.com/os/linux/" target="_blank">Linux</a>   2.6.x下的并发非阻塞TCP网络编程，不跨平台，不支持udp和ipv6。吞吐量方面muduo比libevent2快18%，在事件处理效率方 面，muduo与libevent2总体比较接近，muduo吞吐量比boost.asio高15%以上。性能方面作为解决大数据吞吐量很有优势，但是对 平台和网络协议支持方面是一个问题。<br /> ACE也是很经典的网络库，出自《C++网络编程》作者之手，设计精妙程度堪称一流，支持协议范围也很广，但是使用复杂度和学习复杂度较高，一直有&#8220;学我者生，用我者死&#8221;的评价。<br /> 需要注意的是他们的定位不同，aio和epoll主要是对异步提供解决方案不是网络库不提供网络支持，而libevent也是主要解决IO的问题只提供简单的http支持，asio和muduo还有ACE一样是高性能网络库。</div><img src ="http://www.cppblog.com/guojingjia2006/aggbug/194979.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2012-11-09 15:56 <a href="http://www.cppblog.com/guojingjia2006/archive/2012/11/09/194979.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>免费的C++图形和游戏库</title><link>http://www.cppblog.com/guojingjia2006/archive/2012/06/15/178934.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Fri, 15 Jun 2012 06:29:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2012/06/15/178934.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/178934.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2012/06/15/178934.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/178934.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/178934.html</trackback:ping><description><![CDATA[<div><a style="text-decoration: none;" name="fb_share" type="button_count" href="http://www.facebook.com/sharer.php?u=http%3A%2F%2Fzoomzum.com%2F6-free-c-graphics-and-game-libraries%2F&amp;t=6%20Free%20C%2B%2B%20Graphics%20and%20Game%20Libraries%20%7C%20ZoomZum&amp;src=sp"><span "=""><span fbconnectbutton_small"="" style="cursor:pointer;">Share</span></span></a>       <div style="display:inline;float:left; margin:24px 20px 10px 0px">   </div> 						 						<p>C++ is a multi paradigm, free form complied, general purpose  and thus a very powerful language used basically forthe purpose&nbsp;of  programming. This language is regarded as an&nbsp;intermediatelevel language  .The main reason for this is that it consists of both high level as well  aslow level&nbsp;features.</p> <p>It is one of the most popularprogramming languages&nbsp;due to many  reasons. It has application domains which include system  software,&nbsp;device drivers, application software and many other including  client applications and&nbsp;entertainment software&nbsp;of which the best example  is a video game.</p> <p><a href="http://zoomzum.com/wp-content/uploads/2012/06/C++-Programming.png"><img size-full=""  wp-image-8618"="" title="C++-Programming" src="http://zoomzum.com/wp-content/uploads/2012/06/C++-Programming-e1339530183581.png" alt="" height="380" width="407" /></a></p>  <p>In this list we introduces some highly useful C++ graphics and game  libraries. These libraries has provides a great interface to add these  functionality to their project or application easily. C++ users would  love to use these libraries for their next project.</p> <p>Today we are going to share C++ graphic and games Libraries for  developers, i hope these libraries would help developers a lot in their  next project to make impressive and attractive layout for  theirnest&nbsp;applications. Visit this list and share your thought in  our&nbsp;comment&nbsp;section below.</p>   <h3>1) A<a href="http://www.antigrain.com/index.html" target="_blank">ntigrain</a></h3> <p>Anti-Grain&nbsp;Geometry&nbsp;(AGG) is an Open Source, free of charge graphic  library, written in industrially standard&nbsp;C++. The terms and conditions  of use&nbsp;AGG&nbsp;are described on&nbsp;The License&nbsp;page.&nbsp;AGG&nbsp;doesn&#8217;t depend on any  graphic API or technology. Basically, you can think of&nbsp;AGG&nbsp;as of a  rendering engine that produces pixel images in memory from some  vectorial data.</p> <p><a href="http://zoomzum.com/wp-content/uploads/2012/06/antigrain.png"><img size-full=""  wp-image-8610"="" title="antigrain" src="http://zoomzum.com/wp-content/uploads/2012/06/antigrain-e1339525678913.png" alt="" height="352" width="580" /></a></p> <h3>2)&nbsp;<a href="http://www.amanith.org/project.html" target="_blank">Amanith</a></h3> <p><strong>AmanithVG SRE</strong>&nbsp;is a pure  software solution that grants a superlative vector graphics quality  without to sacrifice performance on any kind of architecture / platform.  Thanks to its original polygon rasterization algorithm and dedicated  optimized scanline fillers, this engine constitues the fastest OpenVG  software rendering solution available on the market.</p> <p><a href="http://zoomzum.com/wp-content/uploads/2012/06/amanith.png"><img size-full=""  wp-image-8611"="" title="amanith" src="http://zoomzum.com/wp-content/uploads/2012/06/amanith-e1339526279685.png" alt="" height="352" width="580" /></a></p> <h3>3)&nbsp;<a href="http://www.codehead.co.uk/cbfg/" target="_blank">Codehead</a></h3> <p><a href="http://zoomzum.com/wp-content/uploads/2012/06/codehead.png"><img size-full=""  wp-image-8612"="" title="codehead" src="http://zoomzum.com/wp-content/uploads/2012/06/codehead-e1339526688721.png" alt="" height="352" width="580" /></a></p> <h3>4)&nbsp;<a href="http://www.oscilloscope-lib.com/" target="_blank">Oscilloscope Lib</a></h3> <p><a href="http://zoomzum.com/wp-content/uploads/2012/06/lib.png"><img size-full=""  wp-image-8613"="" title="lib" src="http://zoomzum.com/wp-content/uploads/2012/06/lib-e1339527087595.png" alt="" height="352" width="580" /></a></p> <h3>5)&nbsp;<a href="http://www.libsdl.org/" target="_blank">Lib SDL</a></h3> <p>Simple DirectMedia Layer is a  cross-platform multimedia library designed to provide low level access  to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D  video framebuffer. It is used by MPEG playback software, emulators, and  many popular games, including the award winning Linux port of  &#8220;Civilization: Call To Power.&#8221;</p> <p><a href="http://zoomzum.com/wp-content/uploads/2012/06/libsdl.png"><img size-full=""  wp-image-8614"="" title="libsdl" src="http://zoomzum.com/wp-content/uploads/2012/06/libsdl-e1339527400685.png" alt="" height="352" width="580" /></a></p> <h3>6)&nbsp;<a href="http://www.ogre3d.org/" target="_blank">Ogre 3d</a></h3> <p>OGRE (<strong>O</strong>bject-Oriented&nbsp;<strong>G</strong>raphics&nbsp;<strong>R</strong>endering&nbsp;<strong>E</strong>ngine)  is a scene-oriented, flexible 3D engine written in C++ designed to make  it easier and more intuitive for developers to produce applications  utilising hardware-accelerated 3D graphics. The class library abstracts  all the details of using the underlying system libraries like Direct3D  and OpenGL and provides an interface based on world objects and other  intuitive classes.</p> <p><a href="http://zoomzum.com/wp-content/uploads/2012/06/ogre3d.png"><img size-full=""  wp-image-8615"="" title="ogre3d" src="http://zoomzum.com/wp-content/uploads/2012/06/ogre3d-e1339528030232.png" alt="" height="352" width="580" /></a></p><p>转自:<div>http://zoomzum.com/6-free-c-graphics-and-game-libraries/</div><br /><a href="http://zoomzum.com/wp-content/uploads/2012/06/ogre3d.png"></a></p></div><img src ="http://www.cppblog.com/guojingjia2006/aggbug/178934.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2012-06-15 14:29 <a href="http://www.cppblog.com/guojingjia2006/archive/2012/06/15/178934.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c/c++通用内存泄漏检测框架GMFD(General Memory Fault Detection Framework)</title><link>http://www.cppblog.com/guojingjia2006/archive/2012/01/16/164246.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Mon, 16 Jan 2012 05:03:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2012/01/16/164246.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/164246.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2012/01/16/164246.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/164246.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/164246.html</trackback:ping><description><![CDATA[<p><strong><span style="font-size: 24px">1 背景：</span></strong><br /><em>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x86平台有完善的用户态检测内存工具比如valgrind等，可以监控程序运行中详细的内存信息，从而精确定位内存问题。然而随着新平台的快速诞生（比如Tilera的TilePro64 CPU)，这些工具不能被及时地移植，导致新平台缺乏相应的手段来定位内存错误，如内存越界，泄漏等，而只能使用粗粒度的方法top，free 等指令观察进程的动态内存总额。其缺点是粒度太粗，而且内存的总数变化有很多原因引起，在复杂的系统里，很难精确定位内存问题的根源，甚至会漏报错报，这严重影响了新平台（如Tilera)开发与测试的效率。针对这个问题，我们提出了一个通用的新平台针对c/c++内存错误检测框架。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 该框架可适用于任何平台。其通过重写标准库的内存分配和释放函数（如malloc, new, new[], free,delete,delete[]等）, 以及维护一个全局的内存分配map数据结构实现。重写后的内存分配比如my_malloc首先调用系统malloc功能，然后记录每一次malloc执行过程中的内存操作信息（包括文件名、行号以及内存尺寸，函数调用栈），以指针值为 key值，存进维护的全局map表。而重写的my_free则是根据传入的指针值在 map 中查找相应的数据项并将之删除，而后调用系统的free 将指针所指向的内存块释放。这样当程序退出的时候，map 中的剩余的数据项就是我们期望检测的内存泄漏信息。我们可以输出泄漏内存块的详细日志，比如文件名，行号等等。这将大大提高类似Tilera平台的内存问题追查效率，提高开发和测试的速度和质量。</em><br /><strong><span style="font-size: 24px">2 基本原理：</span></strong><br />1)&nbsp;&nbsp; &nbsp;通过重写非共享内存分配释放函数malloc, new, new[]，free,delete,delete[]截获 它们在执行过程中的内存操作信息。重载形式如下：<br />&#8251;&nbsp;&nbsp; void* malloc( size_t nSize, char* pszFileName, int nLineNum )<br />&#8251; &nbsp; void* new( size_t nSize, char* pszFileName, int nLineNum )<br />&#8251; &nbsp; void* operator new[]( size_t nSize, char* pszFileName, int nLineNum )<br />&#8251; &nbsp; void free( void *ptr )<br />&#8251; &nbsp; void delete( void *ptr )<br />&#8251; &nbsp; void operator delete[]( void *ptr )<br /><br />2)&nbsp;&nbsp; &nbsp;通过重写共享内存分配释放函数mspace_malloc，mspace_free，重写形式如下：<br /><br />&#8251; &nbsp; void* my_mspace_malloc( mspace msp,unsigned int Size, char* pszFileName, int nLineNum )<br />&#8251; &nbsp; void my_mspace_free(mspace msp, void *ptr )<br /><br />3)&nbsp;&nbsp; &nbsp;我们对malloc, new, new[]，mspace_malloc进行了重载，参数包括size_t nSize、文件名和行号，这里的文件名和行号就是这次malloc, new, new[]，mspace_malloc操作符被调用时所在的文件名和行号，这个信息将在发现内存泄漏时输出，以帮助定位泄漏具体位置。对于 free,delete,delete[]，mspace_free参数为指针地址。<br /><strong><span style="font-size: 24px">3 实例：</span></strong><br />以My_malloc, My_free为例，重写函数结构如下：<br />&nbsp;<span><img class="blogimg" border="0" src="http://hiphotos.baidu.com/baiduqa/pic/item/40392d9649d5cd72d21b70e9.jpg" small="0"  alt="" /></span><br />1.&nbsp;&nbsp; &nbsp;在重写的my_malloc函数版本中，我们将调用malloc 的原始版本并将相应的 size_t 参数传入，然后，我们将malloc的原始版本返回的指针值以及该次分配所在的文件名和行号信息记录下来，这里采用STL 的 map数据结构存储，以指针值为 key 值，文件名，行号等信息作为一个结构体是value值。<br />My_free重写函数结构如下：<br /><span><img class="blogimg" border="0" src="http://hiphotos.baidu.com/baiduqa/pic/item/f45f8f2fba1a9858349bf7c2.jpg" small="0"  alt="" /></span><br />&nbsp;<br />2.&nbsp;&nbsp; &nbsp;当my_free 被调用时，我们根据传入的指针值在 map 中找到相应的数据项并将之删除，而后调用 free 将指针所指向的内存块释放。这样当程序退出的时候，map 中的剩余的数据项就是我们企图检测的内存泄漏信息。<br /><strong><span style="font-size: 24px">4 实现关键点：</span></strong><br /><strong>1)&nbsp;&nbsp; &nbsp;如何取得内存分配代码所在的文件名和行号？</strong><br />利用 C 的预编译宏 __FILE__ 和 __LINE__，这两个宏将在编译时在指定位置展开为该文件的文件名和该行的行号<br /><strong>2)&nbsp;&nbsp; &nbsp;利用宏定义开关决定走普通分支还是内存检测分支？</strong><br />#if defined( MEM_DEBUG )<br />#define malloc DEBUG_MALLOC<br />#define free DEBUG_FREE<br />#endif <br /><strong>3)&nbsp;&nbsp; &nbsp;何时创建用于存储内存数据的 map 数据结构，如何管理，何时打印内存泄漏信息？</strong><br />设计一个类来封装这个 map 以及对它的插入删除操作，然后构造这个类的一个全局对象（appMemory），在全局对象（appMemory）的构造函数中创建并初始化这个数据结 构，而在其析构函数中对数据结构中剩余数据进行分析和输出。new 中将调用这个全局对象的 insert 接口将指针、文件名、行号、内存块大小等信息以指针值为 key 记录到 map 中，在delete 中调用 erase 接口将对应指针值的 map 中的数据项删除，同时对 map 的访问需要进行互斥同步，因为同一时间可能会有多个进程进行堆上的内存操作。<br /><strong>4)&nbsp;&nbsp; &nbsp;如何为非共享内存申请map？如何为共享内存申请map？</strong><br />非共享内存的map,对于多进程则有多个map，可按（3）的方法处理。而对于共享内存，可能A进程申请到B进程才释放，但是每个进程一个map,我们去扫描这些每个map时就会出现误报的现象，因此需要采取将map放入共享内存方法：我们申请一块共享内存区域为map,这个map对各进程是共享的。当程序中各进程调用共享内存时，将各进程分配的指针及文件名行号等详细信息存进这共享的map。程序结束时，扫描该共享的map,就能得到未释放的信息。将 map放入共享内存使用c++标准库时需要我们自己实现一个基于共享内存的allocator，替换map默认的allocator，在这个allocator中实现map的内存分配方案。也可以使用boost库（1.35以上版本），它增加了一个叫做boost::interprocess的库，具体可参考http://blog.cong.co/stl-alloc.html<br /><strong>5)&nbsp;&nbsp; &nbsp;如何使用该工具？</strong><br />内存泄露检测框架提供接口libmemck.h，内容如下</p>
<p><span><img class="blogimg" src="http://hiphotos.baidu.com/baiduqa/pic/item/5bfab41594ab096d4a90a7fb.jpg"  alt="" /></span><br />&nbsp;在被测试程序里包含如下代码即可使用<br /><strong>&nbsp;<span><img class="blogimg" border="0" src="http://hiphotos.baidu.com/baiduqa/pic/item/2ea7671390a1f77cb9127bc4.jpg" small="0"  alt="" /></span><br />6)&nbsp;&nbsp; &nbsp;何时如何捕获信号，生成leak文件？</strong><br />定义一个全局的类得对象，在该类得构造函数里通过signal函数捕获SIGINT、SIGABRT、SIGFPE、SIGTERM信号，当捕获到这些信号其中之一时，开始扫描map并将map剩余信息写入leak文件展示。<br /><strong>7)&nbsp;&nbsp; &nbsp;对临界资源的控制？</strong><br />共享内存的各进程共享的map，各进程间进行读写操作需要加锁，我们这里采用的是信号灯实现。<br />非共享内存各个进程对应的map，在各进程进行插入删除操作时也需要加锁实现<br /><strong>8)&nbsp;&nbsp; &nbsp;程序中malloc作为函数指针？</strong><br />由于将原型malloc(size)重写为my_malloc(size，__FILE__,__LINE__),这样由于函数类型不一致，导致程序调用该工具时编译无法通过，真对这种情况的解决办法为：重写malloc(size)为my_malloc_p(size)这样除了文件名和行号无法得知外，泄露的多少内存可以报出。<br /><br />转自<a href="http://hi.baidu.com/baiduqa/blog/item/e4c991c5ef46e5c7d10060fb.html">http://hi.baidu.com/baiduqa/blog/item/e4c991c5ef46e5c7d10060fb.html</a></p><img src ="http://www.cppblog.com/guojingjia2006/aggbug/164246.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2012-01-16 13:03 <a href="http://www.cppblog.com/guojingjia2006/archive/2012/01/16/164246.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>&lt;转&gt;boost::any的用法、优点和缺点以及源代码分析 </title><link>http://www.cppblog.com/guojingjia2006/archive/2011/06/16/148802.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Thu, 16 Jun 2011 10:32:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2011/06/16/148802.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/148802.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2011/06/16/148802.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/148802.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/148802.html</trackback:ping><description><![CDATA[<div class="clear"></div>
<div class="postBody">
<div id="cnblogs_post_body">01.#include &lt;iostream&gt;&nbsp;&nbsp; <br />02.#include &lt;list&gt;&nbsp;&nbsp; <br />03.#include &lt;boost/any.hpp&gt;&nbsp;&nbsp; <br />04.&nbsp; <br />05.typedef std::list&lt;boost::any&gt; list_any;&nbsp;&nbsp; <br />06.&nbsp; <br />07.//关键部分：可以存放任意类型的对象&nbsp;&nbsp; <br />08.void fill_list(list_any&amp; la)&nbsp;&nbsp; <br />09.{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />10.&nbsp;&nbsp;&nbsp; la.push_back(10);//存放常数&nbsp;&nbsp;&nbsp; <br />11.&nbsp;&nbsp;&nbsp; la.push_back( std::string("dyunze") );//存放字符串对象；注意la.push_back(&#8220;dyunze&#8221;)错误，因为会被当错字符串数组&nbsp;&nbsp; <br />12.}&nbsp;&nbsp; <br />13.&nbsp; <br />14.//根据类型进行显示&nbsp;&nbsp; <br />15.void show_list(list_any&amp; la)&nbsp;&nbsp; <br />16.{&nbsp;&nbsp; <br />17.&nbsp;&nbsp;&nbsp; list_any::iterator it;&nbsp;&nbsp; <br />18.&nbsp;&nbsp;&nbsp; boost::any anyone;&nbsp;&nbsp; <br />19.&nbsp; <br />20.&nbsp;&nbsp;&nbsp; for( it = la.begin(); it != la.end(); it++ )&nbsp;&nbsp; <br />21.&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />22.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; anyone = *it;&nbsp;&nbsp; <br />23.&nbsp; <br />24.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( anyone.type() == typeid(int) )&nbsp;&nbsp; <br />25.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::cout&lt;&lt;boost::any_cast&lt;int&gt;(*it)&lt;&lt;std::endl;&nbsp;&nbsp; <br />26.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if( anyone.type() == typeid(std::string) )&nbsp;&nbsp; <br />27.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::cout&lt;&lt;boost::any_cast&lt;std::string&gt;(*it).c_str()&lt;&lt;std::endl;&nbsp;&nbsp; <br />28.&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; <br />29.}&nbsp;&nbsp; <br />30.&nbsp; <br />31.int main()&nbsp;&nbsp; <br />32.{&nbsp;&nbsp; <br />33.&nbsp;&nbsp;&nbsp; list_any la;&nbsp;&nbsp; <br />34.&nbsp;&nbsp;&nbsp; fill_list(la);&nbsp;&nbsp; <br />35.&nbsp;&nbsp;&nbsp; show_list(la);&nbsp;&nbsp; <br />36.&nbsp; <br />37.&nbsp;&nbsp;&nbsp; return 0;&nbsp;&nbsp; <br />38.}&nbsp; <br />#include &lt;iostream&gt;<br />#include &lt;list&gt;<br />#include &lt;boost/any.hpp&gt;<br /><br />typedef std::list&lt;boost::any&gt; list_any;<br /><br />//关键部分：可以存放任意类型的对象<br />void fill_list(list_any&amp; la)<br />{&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; la.push_back(10);//存放常数 <br />&nbsp;&nbsp;&nbsp; la.push_back( std::string("dyunze") );//存放字符串对象；注意la.push_back(&#8220;dyunze&#8221;)错误，因为会被当错字符串数组<br />}<br /><br />//根据类型进行显示<br />void show_list(list_any&amp; la)<br />{<br />&nbsp;&nbsp;&nbsp; list_any::iterator it;<br />&nbsp;&nbsp;&nbsp; boost::any anyone;<br /><br />&nbsp;&nbsp;&nbsp; for( it = la.begin(); it != la.end(); it++ )<br />&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; anyone = *it;<br /><br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if( anyone.type() == typeid(int) )<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; std::cout&lt;&lt;boost::any_cast&lt;int&gt;(*it)&lt;&lt;std::endl;<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; else if( anyone.type() == typeid(std::string) )<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; std::cout&lt;&lt;boost::any_cast&lt;std::string&gt;(*it).c_str()&lt;&lt;std::endl;<br />&nbsp;&nbsp;&nbsp; }<br />}<br /><br />int main()<br />{<br />&nbsp;&nbsp;&nbsp; list_any la;<br />&nbsp;&nbsp;&nbsp; fill_list(la);<br />&nbsp;&nbsp;&nbsp; show_list(la);<br /><br />&nbsp;&nbsp;&nbsp; return 0;<br />} <br /><br />boost::any的优点：<br /><br />&nbsp;&nbsp;&nbsp;&nbsp; 对设计模式理解的朋友都会知道合成模式。因为多态只有在使用指针或引用的情况下才能显现，所以std容器中只能存放指针或引用（但实际上只能存放指针，无法存放引用，这个好像是c++的不足吧）。如：<br /><br />&nbsp;&nbsp;&nbsp;&nbsp; std::list&lt;BaseClass*&gt; mylist;<br /><br />这样，我们就要对指针所指向内容的生存周期操心(可能需要程序员适时删除申请的内存；但是由于存放指针，插入/删除的效率高)，而使用boost::any就可能避免这种情况，因为我们可以存放类型本身（当然存放指针也可以）。这是boost::any的优点之一。<br /><br />&nbsp;&nbsp;&nbsp; boost::any另一个优点是可以存放任何类型。而前面提到的mylist只能存放BaseClass类指针以及其继承类的指针。<br /><br />boost::any的缺点：<br /><br />&nbsp;&nbsp;&nbsp; 由于boost::any可以存放任何类型，自然它用不了多态特性，没有统一的接口，所以在获取容器中的元素时需要实现判别元素的真正类型，这增加了程序员的负担。与面向对象编程思想有些矛盾，但整个标准c++模板库何尝不是如此，用那些牛人的话来说，是&#8220;有益补充&#8221;。<br /><br />&nbsp;&nbsp; 总之，有利必有弊，没有十全十美的。<br /><br />&nbsp;&nbsp; <br /><br />分析并模仿boost::any：<br /><br />&nbsp;&nbsp;&nbsp;&nbsp; 读了一下boost::any的源代码，并模仿一下其实现(相当一部分时拷贝原代码)，下面是代码(只包含必要功能)。<br /><br />实现any的功能主要由三部分组成：<br />1）any类<br />2）真正保存数据的holder类及其基类placeholder<br />3）获取真正数据的模板函数any_cast，类型转换的功能。<br /><br />view plaincopy to clipboardprint?<br />01.#include &lt;iostream&gt;&nbsp;&nbsp; <br />02.#include &lt;list&gt;&nbsp;&nbsp; <br />03.#include &lt;cassert&gt;&nbsp;&nbsp; <br />04.&nbsp; <br />05.//自定义的any类&nbsp;&nbsp; <br />06.class any&nbsp;&nbsp; <br />07.{&nbsp;&nbsp; <br />08.public:&nbsp;&nbsp; <br />09.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />10.&nbsp;&nbsp;&nbsp; //保存真正数据的接口类&nbsp;&nbsp; <br />11.&nbsp;&nbsp;&nbsp; class placeholder&nbsp;&nbsp; <br />12.&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp; <br />13.&nbsp;&nbsp;&nbsp; public:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />14.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual ~placeholder()&nbsp;&nbsp; <br />15.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp; <br />16.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; <br />17.&nbsp;&nbsp;&nbsp; public:&nbsp;&nbsp;&nbsp; <br />18.&nbsp; <br />19.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual const std::type_info &amp; type() const = 0;&nbsp;&nbsp; <br />20.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual placeholder * clone() const = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />21.&nbsp;&nbsp;&nbsp; };&nbsp;&nbsp; <br />22.&nbsp; <br />23.&nbsp;&nbsp;&nbsp; //真正保存和获取数据的类。&nbsp;&nbsp; <br />24.&nbsp;&nbsp;&nbsp; template&lt;typename ValueType&gt;&nbsp;&nbsp; <br />25.&nbsp;&nbsp;&nbsp; class holder : public placeholder&nbsp;&nbsp; <br />26.&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp; <br />27.&nbsp;&nbsp;&nbsp; public:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />28.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; holder(const ValueType &amp; value): held(value)&nbsp;&nbsp; <br />29.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp; <br />30.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; <br />31.&nbsp; <br />32.&nbsp;&nbsp;&nbsp; public:&nbsp;&nbsp;&nbsp; <br />33.&nbsp; <br />34.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual const std::type_info &amp; type() const&nbsp; <br />35.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp; <br />36.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return typeid(ValueType);&nbsp;&nbsp; <br />37.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; <br />38.&nbsp; <br />39.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual placeholder * clone() const&nbsp; <br />40.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp; <br />41.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new holder(held);//使用了原型模式&nbsp;&nbsp; <br />42.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; <br />43.&nbsp; <br />44.&nbsp;&nbsp;&nbsp; public:&nbsp;&nbsp;&nbsp; <br />45.&nbsp; <br />46.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //真正的数据，就保存在这里&nbsp;&nbsp; <br />47.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ValueType held;&nbsp;&nbsp; <br />48.&nbsp;&nbsp;&nbsp; };&nbsp;&nbsp; <br />49.&nbsp; <br />50.public:&nbsp;&nbsp; <br />51.&nbsp; <br />52.&nbsp;&nbsp;&nbsp; any(): content(NULL)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />53.&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />54.&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; <br />55.&nbsp; <br />56.&nbsp;&nbsp;&nbsp; //模板构造函数，参数可以是任意类型，真正的数据保存在content中&nbsp;&nbsp; <br />57.&nbsp;&nbsp;&nbsp; template&lt;typename ValueType&gt;&nbsp;&nbsp; <br />58.&nbsp;&nbsp;&nbsp; any(const ValueType &amp; value): content(new holder&lt;ValueType&gt;(value))&nbsp;&nbsp; <br />59.&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp; <br />60.&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp; <br />61.&nbsp; <br />62.&nbsp;&nbsp;&nbsp; //拷贝构造函数&nbsp;&nbsp; <br />63.&nbsp;&nbsp;&nbsp; any(const any &amp; other)&nbsp;&nbsp; <br />64.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : content(other.content ? other.content-&gt;clone() : 0)&nbsp;&nbsp; <br />65.&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp; <br />66.&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; <br />67.&nbsp; <br />68.&nbsp;&nbsp;&nbsp; //析构函数，删除保存数据的content对象&nbsp;&nbsp; <br />69.&nbsp;&nbsp;&nbsp; ~any()&nbsp;&nbsp; <br />70.&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp; <br />71.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(NULL != content)&nbsp;&nbsp; <br />72.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delete content;&nbsp;&nbsp; <br />73.&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; <br />74.&nbsp; <br />75.private:&nbsp;&nbsp; <br />76.&nbsp;&nbsp;&nbsp; //一个placeholde对象指针，指向其子类folder的一个实现&nbsp;&nbsp; <br />77.&nbsp;&nbsp;&nbsp; // 即content( new holder&lt;ValueType&gt;(value) )语句&nbsp;&nbsp; <br />78.&nbsp;&nbsp;&nbsp; placeholder* content;&nbsp;&nbsp; <br />79.&nbsp; <br />80.&nbsp;&nbsp;&nbsp; template&lt;typename ValueType&gt; friend ValueType any_cast(const any&amp; operand);&nbsp;&nbsp; <br />81.public:&nbsp;&nbsp;&nbsp; <br />82.&nbsp; <br />83.&nbsp;&nbsp;&nbsp; //查询真实数据的类型。&nbsp;&nbsp; <br />84.&nbsp;&nbsp;&nbsp; const std::type_info &amp; type() const&nbsp; <br />85.&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp; <br />86.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return content ? content-&gt;type() : typeid(void);&nbsp;&nbsp; <br />87.&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; <br />88.};&nbsp;&nbsp; <br />89.&nbsp; <br />90.&nbsp; <br />91.//获取content-&gt;helder数据的方法。用来获取真正的数据&nbsp;&nbsp; <br />92.template&lt;typename ValueType&gt;&nbsp;&nbsp; <br />93.ValueType any_cast(const any&amp; operand)&nbsp;&nbsp; <br />94.{&nbsp;&nbsp; <br />95.&nbsp;&nbsp;&nbsp; assert( operand.type() == typeid(ValueType) );&nbsp;&nbsp; <br />96.&nbsp;&nbsp;&nbsp; return static_cast&lt;any::holder&lt;ValueType&gt; *&gt;(operand.content)-&gt;held;&nbsp;&nbsp; <br />97.}&nbsp;&nbsp; <br />98.&nbsp; <br />99.//下代码是使用示例&nbsp;&nbsp; <br />100.&nbsp; <br />101.typedef std::list&lt;any&gt; list_any;&nbsp;&nbsp; <br />102.&nbsp; <br />103.void fill_list(list_any&amp; la)&nbsp;&nbsp; <br />104.{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />105.&nbsp;&nbsp;&nbsp; la.push_back(10);//存放常数；调用了any的模板构造函数，下同&nbsp;&nbsp; <br />106.&nbsp;&nbsp;&nbsp; la.push_back( std::string("我是string") );//存放字符串对象；注意la.push_back(&#8220;dyunze&#8221;)错误，因为会被当错字符串数组&nbsp;&nbsp; <br />107.&nbsp; <br />108.&nbsp;&nbsp;&nbsp; char* p = "我是常量区字符串abc";&nbsp;&nbsp; <br />109.&nbsp;&nbsp;&nbsp; la.push_back(p);//可以存放指针，但要注意指针的失效问题&nbsp;&nbsp; <br />110.}&nbsp;&nbsp; <br />111.&nbsp; <br />112.//根据类型进行显示&nbsp;&nbsp; <br />113.void show_list(list_any&amp; la)&nbsp;&nbsp; <br />114.{&nbsp;&nbsp; <br />115.&nbsp;&nbsp;&nbsp; list_any::iterator it;&nbsp;&nbsp; <br />116.&nbsp; <br />117.&nbsp;&nbsp;&nbsp; for( it = la.begin(); it != la.end(); it++ )&nbsp;&nbsp; <br />118.&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />119.&nbsp; <br />120.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( (*it).type() == typeid(int) )&nbsp;&nbsp; <br />121.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::cout&lt;&lt;any_cast&lt;int&gt;(*it)&lt;&lt;std::endl;&nbsp;&nbsp; <br />122.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if( (*it).type() == typeid(std::string) )&nbsp;&nbsp; <br />123.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::cout&lt;&lt;any_cast&lt;std::string&gt;(*it).c_str()&lt;&lt;std::endl;&nbsp;&nbsp; <br />124.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if( (*it).type() == typeid(char*) )&nbsp;&nbsp; <br />125.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::cout&lt;&lt;any_cast&lt;char*&gt;(*it)&lt;&lt;std::endl;&nbsp;&nbsp; <br />126.&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; <br />127.}&nbsp;&nbsp; <br />128.&nbsp; <br />129.int main()&nbsp;&nbsp; <br />130.{&nbsp;&nbsp; <br />131.&nbsp;&nbsp;&nbsp; list_any la;&nbsp;&nbsp; <br />132.&nbsp;&nbsp;&nbsp; fill_list(la);&nbsp;&nbsp; <br />133.&nbsp;&nbsp;&nbsp; show_list(la);&nbsp;&nbsp; <br />134.&nbsp; <br />135.&nbsp;&nbsp;&nbsp; return 0;&nbsp;&nbsp; <br />136.}&nbsp; <br /><br />&nbsp;boost::any是一个很有趣的类，刚刚开始我还以为其就是一个variant类型，<br />能够将任意类型值保存进去，能够以任意类型值读出来，不过我错了&nbsp;:(<br />&nbsp;&nbsp;boost::any的作者认为，所谓generic&nbsp;type有三个层面的解释方法：<br />&nbsp;&nbsp;1.类似variant类型那样任意进行类型转换，可以保存一个(int)5进去，<br />&nbsp;&nbsp;&nbsp;&nbsp;读一个(string)"5"出来。Win下面的VARIANT类型是以一个巨大的<br />&nbsp;&nbsp;&nbsp;&nbsp;union实现的类似功能，使用灵活但效率较低<br />&nbsp;&nbsp;2.区别对待包含值的类型，保存一个(int)5进去，不会被隐式转换为<br />&nbsp;&nbsp;&nbsp;&nbsp;(string)'5'或者(double)5.0，这样效率较高且类型安全，<br />&nbsp;&nbsp;&nbsp;&nbsp;不必担心ambiguous&nbsp;conversions<br />&nbsp;&nbsp;3.对包含值类型不加区别，例如把所有保存的值强制转换为void&nbsp;*保存<br />&nbsp;&nbsp;&nbsp;&nbsp;读取时再有程序员判断其类型。这样效率虽最高但无法保证类型安全<br />&nbsp;&nbsp;boost::any就选择了第二层面的设计思路，它允许用户将任意类型值保存<br />进一个any类型变量，但内部并不改变值的类型，并提供方法让用户在使用时<br />主动/被动进行类型判断。<br /><br />&nbsp;&nbsp;在实现方面，boost::any使用两层内部类placeholder和holder保存<br />实际类型的值。类placeholder只是一个接口，模板类holder是特定类型<br />的实现。其中type()方法获取实际值类型，即typeid(ValueType);<br />clone()方法获取值的拷贝return&nbsp;new&nbsp;holder(held);<br />&nbsp;&nbsp;virtual&nbsp;const&nbsp;std::type_info&nbsp;&amp;&nbsp;type()&nbsp;const<br />&nbsp;&nbsp;virtual&nbsp;placeholder&nbsp;*&nbsp;clone()&nbsp;const<br />&nbsp;&nbsp;其值的类型信息不象Win的VARIANT那样以专门的字段保存，<br />而是通过模板参数形式静态保存。这样效率更高（仅在编译期），<br /><br />通用性更强（任何类型都可以，真正any）但灵活性不如VARIANT<br />&nbsp;&nbsp;在进行拷贝构造/赋值/swap时，都直接将整个placeholder换掉，<br />这样可以保证值类型的延续性。<br /><br />&nbsp;&nbsp;在使用方面，提供了主动/被动进行类型检测的方法。<br />&nbsp;&nbsp;可以使用any::type()方法主动检测值类型<br />bool&nbsp;is_int(const&nbsp;boost::any&nbsp;&amp;&nbsp;operand)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;operand.type()&nbsp;==&nbsp;typeid(int);<br />}<br />&nbsp;&nbsp;也可以通过any_cast函数被动进行检测。此函数与C++中的*_cast<br />系列关键字有相同的语法规范，尝试进行类型转换，如类型不匹配则对<br />指针转换返回NULL，对引用转换抛出boost::bad_any_cast异常<br />&nbsp;&nbsp;boost::any&nbsp;str&nbsp;=&nbsp;string("12345");<br />&nbsp;&nbsp;try<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;boost::any_cast&lt;int&gt;(str)&nbsp;&lt;&lt;&nbsp;endl;<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;catch(boost::bad_any_cast&nbsp;e)<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;cerr&nbsp;&lt;&lt;&nbsp;e.what()&nbsp;&lt;&lt;&nbsp;endl;<br />&nbsp;&nbsp;}<br /><br /><br />&nbsp;&nbsp;在应用方面，any类型适合于类型不同但使用相关的值。如C++的...<br />形式的函数参数本事不是类型安全的，可以通过vector&lt;any&gt;改造之<br />然后在使用时检测类型是否匹配，如可改造printf为<br />&nbsp;&nbsp;void&nbsp;safe_printf(const&nbsp;char&nbsp;*format,&nbsp;const&nbsp;vector&lt;any&gt;&amp;&nbsp;params)<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;index&nbsp;=&nbsp;0;<br />&nbsp;&nbsp;&nbsp;&nbsp;for(const&nbsp;char&nbsp;*pch&nbsp;=&nbsp;format;&nbsp;*pch;&nbsp;pch++)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch(*pch)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;'%':<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch(*++pch)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;'i':<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;'d':<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(params[index].type()&nbsp;==&nbsp;typeid(int)&nbsp;||<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;params[index].type()&nbsp;==&nbsp;typeid(short))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;...<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;'\':<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;putchar(*pch);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;}<br /><br />附：boost::any.hpp<br />#ifndef&nbsp;BOOST_ANY_INCLUDED<br />#define&nbsp;BOOST_ANY_INCLUDED<br /><br />//&nbsp;what:&nbsp;&nbsp;variant&nbsp;type&nbsp;boost::any<br />//&nbsp;who:&nbsp;&nbsp;&nbsp;contributed&nbsp;by&nbsp;Kevlin&nbsp;Henney,<br />//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;with&nbsp;features&nbsp;contributed&nbsp;and&nbsp;bugs&nbsp;found&nbsp;by<br />//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ed&nbsp;Brey,&nbsp;Mark&nbsp;Rodgers,&nbsp;Peter&nbsp;Dimov,&nbsp;and&nbsp;James&nbsp;Curran<br />//&nbsp;when:&nbsp;&nbsp;July&nbsp;2001<br />//&nbsp;where:&nbsp;tested&nbsp;with&nbsp;BCC&nbsp;5.5,&nbsp;MSVC&nbsp;6.0,&nbsp;and&nbsp;g++&nbsp;2.95<br /><br />#include&nbsp;&lt;algorithm&gt;<br />#include&nbsp;&lt;typeinfo&gt;<br /><br />#include&nbsp;"boost/config.hpp"<br /><br />namespace&nbsp;boost<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;class&nbsp;any<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;public:&nbsp;//&nbsp;structors<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;any()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;content(0)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;template&lt;typename&nbsp;ValueType&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;any(const&nbsp;ValueType&nbsp;&amp;&nbsp;value)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;content(new&nbsp;holder&lt;ValueType&gt;(value))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;any(const&nbsp;any&nbsp;&amp;&nbsp;other)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;content(other.content&nbsp;?&nbsp;other.content-&gt;clone()&nbsp;:&nbsp;0)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;~any()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;content;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;public:&nbsp;//&nbsp;modifiers<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;any&nbsp;&amp;&nbsp;swap(any&nbsp;&amp;&nbsp;rhs)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::swap(content,&nbsp;rhs.content);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;*this;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;template&lt;typename&nbsp;ValueType&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;any&nbsp;&amp;&nbsp;operator=(const&nbsp;ValueType&nbsp;&amp;&nbsp;rhs)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;any(rhs).swap(*this);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;*this;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;any&nbsp;&amp;&nbsp;operator=(const&nbsp;any&nbsp;&amp;&nbsp;rhs)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;any(rhs).swap(*this);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;*this;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;public:&nbsp;//&nbsp;queries<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bool&nbsp;empty()&nbsp;const<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;!content;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;std::type_info&nbsp;&amp;&nbsp;type()&nbsp;const<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;content&nbsp;?&nbsp;content-&gt;type()&nbsp;:&nbsp;typeid(void);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />#ifndef&nbsp;BOOST_NO_MEMBER_TEMPLATE_FRIENDS<br />&nbsp;&nbsp;&nbsp;&nbsp;private:&nbsp;//&nbsp;types<br />#else<br />&nbsp;&nbsp;&nbsp;&nbsp;public:&nbsp;//&nbsp;types&nbsp;(public&nbsp;so&nbsp;any_cast&nbsp;can&nbsp;be&nbsp;non-friend)<br />#endif<br /><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class&nbsp;placeholder<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public:&nbsp;//&nbsp;structors<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;virtual&nbsp;~placeholder()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public:&nbsp;//&nbsp;queries<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;virtual&nbsp;const&nbsp;std::type_info&nbsp;&amp;&nbsp;type()&nbsp;const&nbsp;=&nbsp;0;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;virtual&nbsp;placeholder&nbsp;*&nbsp;clone()&nbsp;const&nbsp;=&nbsp;0;<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;template&lt;typename&nbsp;ValueType&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class&nbsp;holder&nbsp;:&nbsp;public&nbsp;placeholder<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public:&nbsp;//&nbsp;structors<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;holder(const&nbsp;ValueType&nbsp;&amp;&nbsp;value)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;held(value)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public:&nbsp;//&nbsp;queries<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;virtual&nbsp;const&nbsp;std::type_info&nbsp;&amp;&nbsp;type()&nbsp;const<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;typeid(ValueType);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;virtual&nbsp;placeholder&nbsp;*&nbsp;clone()&nbsp;const<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;holder(held);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public:&nbsp;//&nbsp;representation<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ValueType&nbsp;held;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br /><br />#ifndef&nbsp;BOOST_NO_MEMBER_TEMPLATE_FRIENDS<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;private:&nbsp;//&nbsp;representation<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;template&lt;typename&nbsp;ValueType&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;friend&nbsp;ValueType&nbsp;*&nbsp;any_cast(any&nbsp;*);<br /><br />#else<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;public:&nbsp;//&nbsp;representation&nbsp;(public&nbsp;so&nbsp;any_cast&nbsp;can&nbsp;be&nbsp;non-friend)<br /><br />#endif<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;placeholder&nbsp;*&nbsp;content;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;};<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;class&nbsp;bad_any_cast&nbsp;:&nbsp;public&nbsp;std::bad_cast<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;public:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;virtual&nbsp;const&nbsp;char&nbsp;*&nbsp;what()&nbsp;const&nbsp;throw()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;"boost::bad_any_cast:&nbsp;"<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"failed&nbsp;conversion&nbsp;using&nbsp;boost::any_cast";<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;template&lt;typename&nbsp;ValueType&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;ValueType&nbsp;*&nbsp;any_cast(any&nbsp;*&nbsp;operand)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;operand&nbsp;&amp;&amp;&nbsp;operand-&gt;type()&nbsp;==&nbsp;typeid(ValueType)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&amp;static_cast&lt;any::holder&lt;ValueType&gt;&nbsp;*&gt;(operand-&gt;content)-&gt;held<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;0;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;template&lt;typename&nbsp;ValueType&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;ValueType&nbsp;*&nbsp;any_cast(const&nbsp;any&nbsp;*&nbsp;operand)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;any_cast&lt;ValueType&gt;(const_cast&lt;any&nbsp;*&gt;(operand));<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;template&lt;typename&nbsp;ValueType&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;ValueType&nbsp;any_cast(const&nbsp;any&nbsp;&amp;&nbsp;operand)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;ValueType&nbsp;*&nbsp;result&nbsp;=&nbsp;any_cast&lt;ValueType&gt;(&amp;operand);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!result)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;bad_any_cast();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;*result;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />}<br /><br />//&nbsp;Copyright&nbsp;Kevlin&nbsp;Henney,&nbsp;2000,&nbsp;2001,&nbsp;2002.&nbsp;All&nbsp;rights&nbsp;reserved.<br />//<br />//&nbsp;Permission&nbsp;to&nbsp;use,&nbsp;copy,&nbsp;modify,&nbsp;and&nbsp;distribute&nbsp;this&nbsp;software&nbsp;for&nbsp;any<br />//&nbsp;purpose&nbsp;is&nbsp;hereby&nbsp;granted&nbsp;without&nbsp;fee,&nbsp;provided&nbsp;that&nbsp;this&nbsp;copyright&nbsp;and<br />//&nbsp;permissions&nbsp;notice&nbsp;appear&nbsp;in&nbsp;all&nbsp;copies&nbsp;and&nbsp;derivatives.<br />//<br />//&nbsp;This&nbsp;software&nbsp;is&nbsp;provided&nbsp;"as&nbsp;is"&nbsp;without&nbsp;express&nbsp;or&nbsp;implied&nbsp;warranty.<br /><br />#endif<br /><br /></div></div><img src ="http://www.cppblog.com/guojingjia2006/aggbug/148802.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2011-06-16 18:32 <a href="http://www.cppblog.com/guojingjia2006/archive/2011/06/16/148802.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c++ 内存池</title><link>http://www.cppblog.com/guojingjia2006/archive/2011/04/05/143473.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Tue, 05 Apr 2011 12:18:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2011/04/05/143473.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/143473.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2011/04/05/143473.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/143473.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/143473.html</trackback:ping><description><![CDATA[<p><a name=N100A5><span class=atitle>引言</span></a></p>
<p>本书主要针对的是 C++ 程序的性能优化，深入介绍 C++ 程序性能优化的方法和实例。全书由 4 个篇组成，第 1 篇介绍 C++ 语言的对象模型，该篇是优化 C++ 程序的基础；第 2 篇主要针对如何优化 C++ 程序的内存使用；第 3 篇介绍如何优化程序的启动性能；第 4 篇介绍了三类性能优化工具，即内存分析工具、性能分析工具和 I/O 检测工具，它们是测量程序性能的利器。</p>
<p>本章首先简单介绍自定义内存池性能优化的原理，然后列举软件开发中常用的内存池的不同类型，并给出具体实现的实例。</p>
<div class=ibm-alternate-rule></div>
<p class="ibm-ind-link ibm-back-to-top"><a class=ibm-anchor-up-link href="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index6.html?ca=drs-cn#ibm-pcon"><u><font color=#0066cc>回页首</font></u></a></p>
<p><a name=N100B1><span class=atitle>6.1 自定义内存池性能优化的原理</span></a></p>
<div class="ibm-container dw-container-sidebar ibm-alternate-two">
<div class=ibm-container-body>
<p>&#160;</p>
<table border=0 cellSpacing=0 cellPadding=0 width="100%">
    <tbody>
        <tr>
            <td vAlign=top><img border=0 alt=图书信息 src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/cpppface.jpg" width=100 height=127> </td>
            <td vAlign=top><img border=0 alt="" src="http://www.ibm.com/i/c.gif" width=10> </td>
            <td><strong>书名：</strong>《C++应用程序性能优化》 <br><strong>作者：</strong>冯宏华、徐莹、程远、汪磊 等编著 <br><strong>出版社：</strong>电子工业出版社 <br><strong>出版日期：</strong>2007 年 03 月 <br><strong>ISBN：</strong>978-7-121-03831-0 <br><strong>购买：</strong> <a href="http://www.china-pub.com/computers/common/info.asp?id=34206"><u><font color=#0066cc>中国互动出版网</font></u></a>、<a href="http://www.dearbook.com.cn/book/129969"><u><font color=#0066cc>dearbook</font></u></a> </td>
        </tr>
        <tr>
            <td colSpan=3>
            <p><strong>推荐章节:</strong> </p>
            <ul>
                <li><a href="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/"><u><font color=#0066cc>前言</font></u></a> 和 <a href="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/contents.html"><u><font color=#0066cc>目录</font></u></a> </li>
                <li><a href="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index2.html"><u><font color=#0066cc>第 2 章：C++ 语言特性的性能分析</font></u></a> </li>
                <li><a href="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index6.html"><u><font color=#0066cc>第 6 章：内存池</font></u></a> </li>
            </ul>
            <p>&#160;</p>
            <p>更多推荐书籍，请访问 <a href="http://www.ibm.com/developerworks/cn/books/"><u><font color=#0066cc>developerWorks 图书频道</font></u></a>。</p>
            <p>欢迎您对本书提出宝贵的反馈意见。您可以通过本页面最下方的 <a href="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index6.html?ca=drs-cn#rate"><u><font color=#0066cc>建议</font></u></a> 栏目为本文打分，并反馈您的建议和意见。</p>
            <p>如果您对 developerWorks 图书频道有什么好的建议，<a href="http://www.ibm.com/developerworks/cn/books/feedback.html"><u><font color=#0066cc>欢迎您将建议发给我们</font></u></a>。</p>
            </td>
        </tr>
    </tbody>
</table>
<p>&#160;</p>
</div>
</div>
<p>如前所述，读者已经了解到"堆"和"栈"的区别。而在编程实践中，不可避免地要大量用到堆上的内存。例如在程序中维护一个链表的数据结构时，每次新增或者删除一个链表的节点，都需要从内存堆上分配或者释放一定的内存；在维护一个动态数组时，如果动态数组的大小不能满足程序需要时，也要在内存堆上分配新的内存空间。</p>
<p><a name=N10145><span class=smalltitle>6.1.1 默认内存管理函数的不足</span></a></p>
<p>利用默认的内存管理函数new/delete或malloc/free在堆上分配和释放内存会有一些额外的开销。</p>
<p>系统在接收到分配一定大小内存的请求时，首先查找内部维护的内存空闲块表，并且需要根据一定的算法（例如分配最先找到的不小于申请大小的内存块给请求者，或者分配最适于申请大小的内存块，或者分配最大空闲的内存块等）找到合适大小的空闲内存块。如果该空闲内存块过大，还需要切割成已分配的部分和较小的空闲块。然后系统更新内存空闲块表，完成一次内存分配。类似地，在释放内存时，系统把释放的内存块重新加入到空闲内存块表中。如果有可能的话，可以把相邻的空闲块合并成较大的空闲块。</p>
<p>默认的内存管理函数还考虑到多线程的应用，需要在每次分配和释放内存时加锁，同样增加了开销。</p>
<p>可见，如果应用程序频繁地在堆上分配和释放内存，则会导致性能的损失。并且会使系统中出现大量的内存碎片，降低内存的利用率。</p>
<p>默认的分配和释放内存算法自然也考虑了性能，然而这些内存管理算法的通用版本为了应付更复杂、更广泛的情况，需要做更多的额外工作。而对于某一个具体的应用程序来说，适合自身特定的内存分配释放模式的自定义内存池则可以获得更好的性能。</p>
<p><a name=N1015A><span class=smalltitle>6.1.2 内存池的定义和分类</span></a></p>
<p>自定义内存池的思想通过这个"池"字表露无疑，应用程序可以通过系统的内存分配调用预先一次性申请适当大小的内存作为一个内存池，之后应用程序自己对内存的分配和释放则可以通过这个内存池来完成。只有当内存池大小需要动态扩展时，才需要再调用系统的内存分配函数，其他时间对内存的一切操作都在应用程序的掌控之中。</p>
<p>应用程序自定义的内存池根据不同的适用场景又有不同的类型。</p>
<p>从线程安全的角度来分，内存池可以分为单线程内存池和多线程内存池。单线程内存池整个生命周期只被一个线程使用，因而不需要考虑互斥访问的问题；多线程内存池有可能被多个线程共享，因此则需要在每次分配和释放内存时加锁。相对而言，单线程内存池性能更高，而多线程内存池适用范围更广。</p>
<p>从内存池可分配内存单元大小来分，可以分为固定内存池和可变内存池。所谓固定内存池是指应用程序每次从内存池中分配出来的内存单元大小事先已经确定，是固定不变的；而可变内存池则每次分配的内存单元大小可以按需变化，应用范围更广，而性能比固定内存池要低。</p>
<p><a name=N1016C><span class=smalltitle>6.1.3 内存池工作原理示例</span></a></p>
<p>下面以固定内存池为例说明内存池的工作原理，如图6-1所示。</p>
<br><a name=N10177><strong>图6-1 固定内存池</strong></a><br><img border=0 alt="图6-1  固定内存池" src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_1.gif" width=498 height=211> <br>
<p>固定内存池由一系列固定大小的内存块组成，每一个内存块又包含了固定数量和大小的内存单元。</p>
<p>如图6-1所示，该内存池一共包含4个内存块。在内存池初次生成时，只向系统申请了一个内存块，返回的指针作为整个内存池的头指针。之后随着应用程序对内存的不断需求，内存池判断需要动态扩大时，才再次向系统申请新的内存块，并把所有这些内存块通过指针链接起来。对于操作系统来说，它已经为该应用程序分配了4个等大小的内存块。由于是大小固定的，所以分配的速度比较快；而对于应用程序来说，其内存池开辟了一定大小，内存池内部却还有剩余的空间。</p>
<p>例如放大来看第4个内存块，其中包含一部分内存池块头信息和3个大小相等的内存池单元。单元1和单元3是空闲的，单元2已经分配。当应用程序需要通过该内存池分配一个单元大小的内存时，只需要简单遍历所有的内存池块头信息，快速定位到还有空闲单元的那个内存池块。然后根据该块的块头信息直接定位到第1个空闲的单元地址，把这个地址返回，并且标记下一个空闲单元即可；当应用程序释放某一个内存池单元时，直接在对应的内存池块头信息中标记该内存单元为空闲单元即可。</p>
<p>可见与系统管理内存相比，内存池的操作非常迅速，它在性能优化方面的优点主要如下。</p>
<p>（1）针对特殊情况，例如需要频繁分配释放固定大小的内存对象时，不需要复杂的分配算法和多线程保护。也不需要维护内存空闲表的额外开销，从而获得较高的性能。</p>
<p>（2）由于开辟一定数量的连续内存空间作为内存池块，因而一定程度上提高了程序局部性，提升了程序性能。</p>
<p>（3）比较容易控制页边界对齐和内存字节对齐，没有内存碎片的问题。</p>
<div class=ibm-alternate-rule></div>
<p class="ibm-ind-link ibm-back-to-top"><a class=ibm-anchor-up-link href="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index6.html?ca=drs-cn#ibm-pcon"><u><font color=#0066cc>回页首</font></u></a></p>
<p><a name=N1019C><span class=atitle>6.2 一个内存池的实现实例</span></a></p>
<p>本节分析在某个大型应用程序实际应用到的一个内存池实现，并详细讲解其使用方法与工作原理。这是一个应用于单线程环境且分配单元大小固定的内存池，一般用来为执行时会动态频繁地创建且可能会被多次创建的类对象或者结构体分配内存。</p>
<p>本节首先讲解该内存池的数据结构声明及图示，接着描述其原理及行为特征。然后逐一讲解实现细节，最后介绍如何在实际程序中应用此内存池，并与使用普通内存函数申请内存的程序性能作比较。</p>
<p><a name=N101A8><span class=smalltitle>6.2.1 内部构造</span></a></p>
<p>内存池类MemoryPool的声明如下：</p>
<br>
<table border=0 cellSpacing=0 cellPadding=0 width="100%">
    <tbody>
        <tr>
            <td class=code-outline>
            <pre class=displaycode>class MemoryPool
            {
            private:
            MemoryBlock*   pBlock;
            USHORT          nUnitSize;
            USHORT          nInitSize;
            USHORT          nGrowSize;
            public:
            MemoryPool( USHORT nUnitSize,
            USHORT nInitSize = 1024,
            USHORT nGrowSize = 256 );
            ~MemoryPool();
            void*           Alloc();
            void            Free( void* p );
            };
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>MemoryBlock为内存池中附着在真正用来为内存请求分配内存的内存块头部的结构体，它描述了与之联系的内存块的使用信息：</p>
<br>
<table border=0 cellSpacing=0 cellPadding=0 width="100%">
    <tbody>
        <tr>
            <td class=code-outline>
            <pre class=displaycode>struct MemoryBlock
            {
            USHORT          nSize;
            USHORT          nFree;
            USHORT          nFirst;
            USHORT          nDummyAlign1;
            MemoryBlock*  pNext;
            char            aData[1];
            static void* operator new(size_t, USHORT nTypes, USHORT nUnitSize)
            {
            return ::operator new(sizeof(MemoryBlock) + nTypes * nUnitSize);
            }
            static void  operator delete(void *p, size_t)
            {
            ::operator delete (p);
            }
            MemoryBlock (USHORT nTypes = 1, USHORT nUnitSize = 0);
            ~MemoryBlock() {}
            };
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>此内存池的数据结构如图6-2所示。</p>
<br><a name=N101CB><strong>图6-2 内存池的数据结构</strong></a><br><img border=0 alt="图6-2  内存池的数据结构" src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_2.gif" width=544 height=369> <br>
<p><a name=N101DB><span class=smalltitle>6.2.2 总体机制</span></a></p>
<p>此内存池的总体机制如下。</p>
<p>（1）在运行过程中，MemoryPool内存池可能会有多个用来满足内存申请请求的内存块，这些内存块是从进程堆中开辟的一个较大的连续内存区域，它由一个MemoryBlock结构体和多个可供分配的内存单元组成，所有内存块组成了一个内存块链表，MemoryPool 的pBlock是这个链表的头。对每个内存块，都可以通过其头部的MemoryBlock结构体的pNext成员访问紧跟在其后面的那个内存块。</p>
<p>（2）每个内存块由两部分组成，即一个MemoryBlock结构体和多个内存分配单元。这些内存分配单元大小固定（由 MemoryPool的nUnitSize表示），MemoryBlock结构体并不维护那些已经分配的单元的信息；相反，它只维护没有分配的自由分配单元的信息。它有两个成员比较重要：nFree和nFirst。nFree记录这个内存块中还有多少个自由分配单元，而nFirst则记录下一个可供分配的单元的编号。每一个自由分配单元的头两个字节（即一个USHORT型值）记录了紧跟它之后的下一个自由分配单元的编号，这样，通过利用每个自由分配单元的头两个字节，一个MemoryBlock中的所有自由分配单元被链接起来。</p>
<p>（3）当有新的内存请求到来时，MemoryPool会通过pBlock遍历MemoryBlock链表，直到找到某个 MemoryBlock所在的内存块，其中还有自由分配单元（通过检测MemoryBlock结构体的nFree成员是否大于0）。如果找到这样的内存块，取得其MemoryBlock的nFirst值（此为该内存块中第1个可供分配的自由单元的编号）。然后根据这个编号定位到该自由分配单元的起始位置（因为所有分配单元大小固定，因此每个分配单元的起始位置都可以通过编号分配单元大小来偏移定位），这个位置就是用来满足此次内存申请请求的内存的起始地址。但在返回这个地址前，需要首先将该位置开始的头两个字节的值（这两个字节值记录其之后的下一个自由分配单元的编号）赋给本内存块的 MemoryBlock的nFirst成员。这样下一次的请求就会用这个编号对应的内存单元来满足，同时将此内存块的MemoryBlock的nFree 递减1，然后才将刚才定位到的内存单元的起始位置作为此次内存请求的返回地址返回给调用者。</p>
<p>（4）如果从现有的内存块中找不到一个自由的内存分配单元（当第1次请求内存，以及现有的所有内存块中的所有内存分配单元都已经被分配时会发生这种情形），MemoryPool就会从进程堆中申请一个内存块（这个内存块包括一个MemoryBlock结构体，及紧邻其后的多个内存分配单元，假设内存分配单元的个数为n，n可以取值MemoryPool中的nInitSize或者nGrowSize），申请完后，并不会立刻将其中的一个分配单元分配出去，而是需要首先初始化这个内存块。初始化的操作包括设置MemoryBlock的nSize为所有内存分配单元的大小（注意，并不包括MemoryBlock结构体的大小）、nFree为n-1（注意，这里是n-1而不是n，因为此次新内存块就是为了满足一次新的内存请求而申请的，马上就会分配一块自由存储单元出去，如果设为n-1，分配一个自由存储单元后无须再将n递减1），nFirst为1（已经知道nFirst为下一个可以分配的自由存储单元的编号。为1的原因与nFree为n-1相同，即立即会将编号为0的自由分配单元分配出去。现在设为1，其后不用修改nFirst的值），MemoryBlock的构造需要做更重要的事情，即将编号为0的分配单元之后的所有自由分配单元链接起来。如前所述，每个自由分配单元的头两个字节用来存储下一个自由分配单元的编号。另外，因为每个分配单元大小固定，所以可以通过其编号和单元大小（MemoryPool的nUnitSize成员）的乘积作为偏移值进行定位。现在唯一的问题是定位从哪个地址开始？答案是MemoryBlock的aData[1]成员开始。因为aData[1]实际上是属于MemoryBlock结构体的（MemoryBlock结构体的最后一个字节），所以实质上，MemoryBlock结构体的最后一个字节也用做被分配出去的分配单元的一部分。因为整个内存块由MemoryBlock结构体和整数个分配单元组成，这意味着内存块的最后一个字节会被浪费，这个字节在图6-2中用位于两个内存的最后部分的浓黑背景的小块标识。确定了分配单元的起始位置后，将自由分配单元链接起来的工作就很容易了。即从aData位置开始，每隔nUnitSize大小取其头两个字节，记录其之后的自由分配单元的编号。因为刚开始所有分配单元都是自由的，所以这个编号就是自身编号加1，即位置上紧跟其后的单元的编号。初始化后，将此内存块的第1个分配单元的起始地址返回，已经知道这个地址就是aData。</p>
<p>（5）当某个被分配的单元因为delete需要回收时，该单元并不会返回给进程堆，而是返回给MemoryPool。返回时，MemoryPool能够知道该单元的起始地址。这时，MemoryPool开始遍历其所维护的内存块链表，判断该单元的起始地址是否落在某个内存块的地址范围内。如果不在所有内存地址范围内，则这个被回收的单元不属于这个MemoryPool；如果在某个内存块的地址范围内，那么它会将这个刚刚回收的分配单元加到这个内存块的MemoryBlock所维护的自由分配单元链表的头部，同时将其nFree值递增1。回收后，考虑到资源的有效利用及后续操作的性能，内存池的操作会继续判断：如果此内存块的所有分配单元都是自由的，那么这个内存块就会从MemoryPool中被移出并作为一个整体返回给进程堆；如果该内存块中还有非自由分配单元，这时不能将此内存块返回给进程堆。但是因为刚刚有一个分配单元返回给了这个内存块，即这个内存块有自由分配单元可供下次分配，因此它会被移到MemoryPool维护的内存块的头部。这样下次的内存请求到来，MemoryPool遍历其内存块链表以寻找自由分配单元时，第1次寻找就会找到这个内存块。因为这个内存块确实有自由分配单元，这样可以减少MemoryPool的遍历次数。</p>
<p>综上所述，每个内存池（MemoryPool）维护一个内存块链表（单链表），每个内存块由一个维护该内存块信息的块头结构（MemoryBlock）和多个分配单元组成，块头结构MemoryBlock则进一步维护一个该内存块的所有自由分配单元组成的"链表"。这个链表不是通过"指向下一个自由分配单元的指针"链接起来的，而是通过"下一个自由分配单元的编号"链接起来，这个编号值存储在该自由分配单元的头两个字节中。另外，第1个自由分配单元的起始位置并不是MemoryBlock结构体"后面的"第1个地址位置，而是MemoryBlock结构体"内部"的最后一个字节aData（也可能不是最后一个，因为考虑到字节对齐的问题），即分配单元实际上往前面错了一位。又因为MemoryBlock结构体后面的空间刚好是分配单元的整数倍，这样依次错位下去，内存块的最后一个字节实际没有被利用。这么做的一个原因也是考虑到不同平台的移植问题，因为不同平台的对齐方式可能不尽相同。即当申请MemoryBlock大小内存时，可能会返回比其所有成员大小总和还要大一些的内存。最后的几个字节是为了"补齐"，而使得 aData成为第1个分配单元的起始位置，这样在对齐方式不同的各种平台上都可以工作。</p>
<p><a name=N101F6><span class=smalltitle>6.2.3 细节剖析</span></a></p>
<p>有了上述的总体印象后，本节来仔细剖析其实现细节。</p>
<p>（1）MemoryPool的构造如下：</p>
<br>
<table border=0 cellSpacing=0 cellPadding=0 width="100%">
    <tbody>
        <tr>
            <td class=code-outline>
            <pre class=displaycode>MemoryPool::MemoryPool( USHORT _nUnitSize,
            USHORT _nInitSize, USHORT _nGrowSize )
            {
            pBlock      = NULL;	            ①
            nInitSize   = _nInitSize;       ②
            nGrowSize   = _nGrowSize;       ③
            if ( _nUnitSize &gt; 4 )
            nUnitSize = (_nUnitSize + (MEMPOOL_ALIGNMENT-1)) &amp; ~(MEMPOOL_ALIGNMENT-1); ④
            else if ( _nUnitSize &lt;= 2 )
            nUnitSize = 2;              ⑤
            else
            nUnitSize = 4;
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>从①处可以看出，MemoryPool创建时，并没有立刻创建真正用来满足内存申请的内存块，即内存块链表刚开始时为空。</p>
<p>②处和③处分别设置"第1次创建的内存块所包含的分配单元的个数"，及"随后创建的内存块所包含的分配单元的个数"，这两个值在MemoryPool创建时通过参数指定，其后在该MemoryPool对象生命周期中一直不变。</p>
<p>后面的代码用来设置nUnitSize，这个值参考传入的_nUnitSize参数。但是还需要考虑两个因素。如前所述，每个分配单元在自由状态时，其头两个字节用来存放"其下一个自由分配单元的编号"。即每个分配单元"最少"有"两个字节"，这就是⑤处赋值的原因。④处是将大于4个字节的大小_nUnitSize往上"取整到"大于_nUnitSize的最小的MEMPOOL_ ALIGNMENT的倍数（前提是MEMPOOL_ALIGNMENT为2的倍数）。如_nUnitSize为11 时，MEMPOOL_ALIGNMENT为8，nUnitSize为16；MEMPOOL_ALIGNMENT为4，nUnitSize为 12；MEMPOOL_ALIGNMENT为2，nUnitSize为12，依次类推。</p>
<p>（2）当向MemoryPool提出内存请求时：</p>
<br>
<table border=0 cellSpacing=0 cellPadding=0 width="100%">
    <tbody>
        <tr>
            <td class=code-outline>
            <pre class=displaycode>void* MemoryPool::Alloc()
            {
            if ( !pBlock )           ①
            {
            &#8230;&#8230;
            }
            MemoryBlock* pMyBlock = pBlock;
            while (pMyBlock &amp;&amp; !pMyBlock-&gt;nFree )②
            pMyBlock = pMyBlock-&gt;pNext;
            if ( pMyBlock )	         ③
            {
            char* pFree = pMyBlock-&gt;aData+(pMyBlock-&gt;nFirst*nUnitSize);
            pMyBlock-&gt;nFirst = *((USHORT*)pFree);
            pMyBlock-&gt;nFree--;
            return (void*)pFree;
            }
            else                    ④
            {
            if ( !nGrowSize )
            return NULL;
            pMyBlock = new(nGrowSize, nUnitSize) FixedMemBlock(nGrowSize, nUnitSize);
            if ( !pMyBlock )
            return NULL;
            pMyBlock-&gt;pNext = pBlock;
            pBlock = pMyBlock;
            return (void*)(pMyBlock-&gt;aData);
            }
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>MemoryPool满足内存请求的步骤主要由四步组成。</p>
<p>①处首先判断内存池当前内存块链表是否为空，如果为空，则意味着这是第1次内存申请请求。这时，从进程堆中申请一个分配单元个数为nInitSize的内存块，并初始化该内存块（主要初始化MemoryBlock结构体成员，以及创建初始的自由分配单元链表，下面会详细分析其代码）。如果该内存块申请成功，并初始化完毕，返回第1个分配单元给调用函数。第1个分配单元以MemoryBlock结构体内的最后一个字节为起始地址。</p>
<p>②处的作用是当内存池中已有内存块（即内存块链表不为空）时遍历该内存块链表，寻找还有"自由分配单元"的内存块。</p>
<p>③处检查如果找到还有自由分配单元的内存块，则"定位"到该内存块现在可以用的自由分配单元处。"定位"以 MemoryBlock结构体内的最后一个字节位置aData为起始位置，以MemoryPool的nUnitSize为步长来进行。找到后，需要修改 MemoryBlock的nFree信息（剩下来的自由分配单元比原来减少了一个），以及修改此内存块的自由存储单元链表的信息。在找到的内存块中，pMyBlock-&gt;nFirst为该内存块中自由存储单元链表的表头，其下一个自由存储单元的编号存放在 pMyBlock-&gt;nFirst指示的自由存储单元（亦即刚才定位到的自由存储单元）的头两个字节。通过刚才定位到的位置，取其头两个字节的值，赋给pMyBlock-&gt;nFirst，这就是此内存块的自由存储单元链表的新的表头，即下一次分配出去的自由分配单元的编号（如果nFree大于零的话）。修改维护信息后，就可以将刚才定位到的自由分配单元的地址返回给此次申请的调用函数。注意，因为这个分配单元已经被分配，而内存块无须维护已分配的分配单元，因此该分配单元的头两个字节的信息已经没有用处。换个角度看，这个自由分配单元返回给调用函数后，调用函数如何处置这块内存，内存池无从知晓，也无须知晓。此分配单元在返回给调用函数时，其内容对于调用函数来说是无意义的。因此几乎可以肯定调用函数在用这个单元的内存时会覆盖其原来的内容，即头两个字节的内容也会被抹去。因此每个存储单元并没有因为需要链接而引入多余的维护信息，而是直接利用单元内的头两个字节，当其分配后，头两个字节也可以被调用函数利用。而在自由状态时，则用来存放维护信息，即下一个自由分配单元的编号，这是一个有效利用内存的好例子。</p>
<p>④处表示在②处遍历时，没有找到还有自由分配单元的内存块，这时，需要重新向进程堆申请一个内存块。因为不是第一次申请内存块，所以申请的内存块包含的分配单元个数为nGrowSize，而不再是nInitSize。与①处相同，先做这个新申请内存块的初始化工作，然后将此内存块插入MemoryPool的内存块链表的头部，再将此内存块的第1个分配单元返回给调用函数。将此新内存块插入内存块链表的头部的原因是该内存块还有很多可供分配的自由分配单元（除非nGrowSize等于1，这应该不太可能。因为内存池的含义就是一次性地从进程堆中申请一大块内存，以供后续的多次申请），放在头部可以使得在下次收到内存申请时，减少②处对内存块的遍历时间。</p>
<p>可以用图6-2的MemoryPool来展示MemoryPool::Alloc的过程。图6-3是某个时刻MemoryPool的内部状态。</p>
<br><a name=N10234><strong>图6-3 某个时刻MemoryPool的内部状态</strong></a><br><img border=0 alt="图6-3  某个时刻MemoryPool的内部状态" src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_3.gif" width=568 height=397> <br>
<p>因为MemoryPool的内存块链表不为空，因此会遍历其内存块链表。又因为第1个内存块里有自由的分配单元，所以会从第1个内存块中分配。检查nFirst，其值为m，这时pBlock-&gt;aData+(pBlock-&gt;nFirst*nUnitSize) 定位到编号为m的自由分配单元的起始位置（用pFree表示）。在返回pFree之前，需要修改此内存块的维护信息。首先将nFree递减1，然后取得 pFree处开始的头两个字节的值（需要说明的是，这里aData处值为k。其实不是这一个字节。而是以aData和紧跟其后的另外一个字节合在一起构成的一个USHORT的值，不可误会）。发现为k，这时修改pBlock的nFirst为k。然后，返回pFree。此时MemoryPool的结构如图 6-4所示。</p>
<br><a name=N10249><strong>图6-4 MemoryPool的结构</strong></a><br><img border=0 alt="图6-4  MemoryPool的结构" src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_4.gif" width=521 height=373> <br>
<p>可以看到，原来的第1个可供分配的单元（m编号处）已经显示为被分配的状态。而pBlock的nFirst已经指向原来m单元下一个自由分配单元的编号，即k。</p>
<p>（3）MemoryPool回收内存时：</p>
<br>
<table border=0 cellSpacing=0 cellPadding=0 width="100%">
    <tbody>
        <tr>
            <td class=code-outline>
            <pre class=displaycode>void MemoryPool::Free( void* pFree )
            {
            &#8230;&#8230;
            MemoryBlock* pMyBlock = pBlock;
            while ( ((ULONG)pMyBlock-&gt;aData &gt; (ULONG)pFree) ||
            ((ULONG)pFree &gt;= ((ULONG)pMyBlock-&gt;aData + pMyBlock-&gt;nSize)) )①
            {
            &#8230;&#8230;
            }
            pMyBlock-&gt;nFree++;                     ②
            *((USHORT*)pFree) = pMyBlock-&gt;nFirst;  ③
            pMyBlock-&gt;nFirst = (USHORT)(((ULONG)pFree-(ULONG)(pBlock-&gt;aData)) / nUnitSize);④
            if (pMyBlock-&gt;nFree*nUnitSize == pMyBlock-&gt;nSize )⑤
            {
            &#8230;&#8230;
            }
            else
            {
            &#8230;&#8230;
            }
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>如前所述，回收分配单元时，可能会将整个内存块返回给进程堆，也可能将被回收分配单元所属的内存块移至内存池的内存块链表的头部。这两个操作都需要修改链表结构。这时需要知道该内存块在链表中前一个位置的内存块。</p>
<p>①处遍历内存池的内存块链表，确定该待回收分配单元（pFree）落在哪一个内存块的指针范围内，通过比较指针值来确定。</p>
<p>运行到②处，pMyBlock即找到的包含pFree所指向的待回收分配单元的内存块（当然，这时应该还需要检查 pMyBlock为NULL时的情形，即pFree不属于此内存池的范围，因此不能返回给此内存池，读者可以自行加上）。这时将pMyBlock的 nFree递增1，表示此内存块的自由分配单元多了一个。</p>
<p>③处用来修改该内存块的自由分配单元链表的信息，它将这个待回收分配单元的头两个字节的值指向该内存块原来的第一个可分配的自由分配单元的编号。</p>
<p>④处将pMyBlock的nFirst值改变为指向这个待回收分配单元的编号，其编号通过计算此单元的起始位置相对pMyBlock的aData位置的差值，然后除以步长（nUnitSize）得到。</p>
<p>实质上，③和④两步的作用就是将此待回收分配单元"真正回收"。值得注意的是，这两步实际上是使得此回收单元成为此内存块的下一个可分配的自由分配单元，即将它放在了自由分配单元链表的头部。注意，其内存地址并没有发生改变。实际上，一个分配单元的内存地址无论是在分配后，还是处于自由状态时，一直都不会变化。变化的只是其状态（已分配/自由），以及当其处于自由状态时在自由分配单元链表中的位置。</p>
<p>⑤处检查当回收完毕后，包含此回收单元的内存块的所有单元是否都处于自由状态，且此内存是否处于内存块链表的头部。如果是，将此内存块整个的返回给进程堆，同时修改内存块链表结构。</p>
<p>注意，这里在判断一个内存块的所有单元是否都处于自由状态时，并没有遍历其所有单元，而是判断nFree乘以 nUnitSize是否等于nSize。nSize是内存块中所有分配单元的大小，而不包括头部MemoryBlock结构体的大小。这里可以看到其用意，即用来快速检查某个内存块中所有分配单元是否全部处于自由状态。因为只需结合nFree和nUnitSize来计算得出结论，而无须遍历和计算所有自由状态的分配单元的个数。</p>
<p>另外还需注意的是，这里并不能比较nFree与nInitSize或nGrowSize的大小来判断某个内存块中所有分配单元都为自由状态，这是因为第1次分配的内存块（分配单元个数为nInitSize）可能被移到链表的后面，甚至可能在移到链表后面后，因为某个时间其所有单元都处于自由状态而被整个返回给进程堆。即在回收分配单元时，无法判定某个内存块中的分配单元个数到底是nInitSize还是nGrowSize，也就无法通过比较nFree与nInitSize或nGrowSize的大小来判断一个内存块的所有分配单元是否都为自由状态。</p>
<p>以上面分配后的内存池状态作为例子，假设这时第2个内存块中的最后一个单元需要回收（已被分配，假设其编号为m，pFree指针指向它），如图6-5所示。</p>
<p>不难发现，这时nFirst的值由原来的0变为m。即此内存块下一个被分配的单元是m编号的单元，而不是0编号的单元（最先分配的是最新回收的单元，从这一点看，这个过程与栈的原理类似，即先进后出。只不过这里的"进"意味着"回收"，而"出"则意味着"分配"）。相应地，m的"下一个自由单元"标记为0，即内存块原来的"下一个将被分配出去的单元"，这也表明最近回收的分配单元被插到了内存块的"自由分配单元链表"的头部。当然，nFree递增1。</p>
<br><a name=N1028B><strong>图6-5 分配后的内存池状态</strong></a><br><img border=0 alt="图6-5  分配后的内存池状态" src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_5.gif" width=458 height=328> <br>
<p>处理至⑥处之前，其状态如图6-6所示。</p>
<br><a name=N102A0><strong>图6-6 处理至⑥处之前的内存池状态</strong></a><br><img border=0 alt="图6-6  处理至⑥处之前的内存池状态" src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_6.gif" width=535 height=365> <br>
<p>这里需要注意的是，虽然pFree被"回收"，但是pFree仍然指向m编号的单元，这个单元在回收过程中，其头两个字节被覆写，但其他部分的内容并没有改变。而且从整个进程的内存使用角度来看，这个m编号的单元的状态仍然是"有效的"。因为这里的"回收"只是回收给了内存池，而并没有回收给进程堆，因此程序仍然可以通过pFree访问此单元。但是这是一个很危险的操作，因为首先该单元在回收过程中头两个字节已被覆写，并且该单元可能很快就会被内存池重新分配。因此回收后通过pFree指针对这个单元的访问都是错误的，读操作会读到错误的数据，写操作则可能会破坏程序中其他地方的数据，因此需要格外小心。</p>
<p>接着，需要判断该内存块的内部使用情况，及其在内存块链表中的位置。如果该内存块中省略号"&#8230;&#8230;"所表示的其他部分中还有被分配的单元，即nFree乘以nUnitSize不等于nSize。因为此内存块不在链表头，因此还需要将其移到链表头部，如图6-7所示。</p>
<br><a name=N102B8><strong>图6-7 因回收引起的MemoryBlock移动</strong></a><br><img border=0 alt="图6-7  因回收引起的MemoryBlock移动" src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_7.gif" width=508 height=333> <br>
<p>如果该内存块中省略号"&#8230;&#8230;"表示的其他部分中全部都是自由分配单元，即nFree乘以nUnitSize等于nSize。因为此内存块不在链表头，所以此时需要将此内存块整个回收给进程堆，回收后内存池的结构如图6-8所示。</p>
<br><a name=N102CD><strong>图6-8 回收后内存池的结构</strong></a><br><img border=0 alt="图6-8  回收后内存池的结构" src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_8.gif" width=322 height=346> <br>
<p>一个内存块在申请后会初始化，主要是为了建立最初的自由分配单元链表，下面是其详细代码：</p>
<br>
<table border=0 cellSpacing=0 cellPadding=0 width="100%">
    <tbody>
        <tr>
            <td class=code-outline>
            <pre class=displaycode>MemoryBlock::MemoryBlock (USHORT nTypes, USHORT nUnitSize)
            : nSize  (nTypes * nUnitSize),
            nFree  (nTypes - 1),                     ④
            nFirst (1),                              ⑤
            pNext  (0)
            {
            char * pData = aData;                  ①
            for (USHORT i = 1; i &lt; nTypes; i++) ②
            {
            *reinterpret_cast&lt;USHORT*&gt;(pData) = i; ③
            pData += nUnitSize;
            }
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>这里可以看到，①处pData的初值是aData，即0编号单元。但是②处的循环中i却是从1开始，然后在循环内部的③处将pData的头两个字节值置为i。即0号单元的头两个字节值为1，1号单元的头两个字节值为2，一直到（nTypes-2）号单元的头两个字节值为（nTypes-1）。这意味着内存块初始时，其自由分配单元链表是从0号开始。依次串联，一直到倒数第2个单元指向最后一个单元。</p>
<p>还需要注意的是，在其初始化列表中，nFree初始化为nTypes-1（而不是nTypes），nFirst初始化为 1（而不是0）。这是因为第1个单元，即0编号单元构造完毕后，立刻会被分配。另外注意到最后一个单元初始并没有设置头两个字节的值，因为该单元初始在本内存块中并没有下一个自由分配单元。但是从上面例子中可以看到，当最后一个单元被分配并回收后，其头两个字节会被设置。</p>
<p>图6-9所示为一个内存块初始化后的状态。</p>
<br><a name=N102F4><strong>图6-9 一个内存块初始化后的状态</strong></a><br><img border=0 alt="图6-9  一个内存块初始化后的状态" src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_9.gif" width=199 height=327> <br>
<p>当内存池析构时，需要将内存池的所有内存块返回给进程堆：</p>
<br>
<table border=0 cellSpacing=0 cellPadding=0 width="100%">
    <tbody>
        <tr>
            <td class=code-outline>
            <pre class=displaycode>MemoryPool::~MemoryPool()
            {
            MemoryBlock* pMyBlock = pBlock;
            while ( pMyBlock )
            {
            &#8230;&#8230;
            }
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p><a name=N10310><span class=smalltitle>6.2.4 使用方法</span></a></p>
<p>分析内存池的内部原理后，本节说明如何使用它。从上面的分析可以看到，该内存池主要有两个对外接口函数，即Alloc和 Free。Alloc返回所申请的分配单元（固定大小内存），Free则回收传入的指针代表的分配单元的内存给内存池。分配的信息则通过 MemoryPool的构造函数指定，包括分配单元大小、内存池第1次申请的内存块中所含分配单元的个数，以及内存池后续申请的内存块所含分配单元的个数等。</p>
<p>综上所述，当需要提高某些关键类对象的申请／回收效率时，可以考虑将该类所有生成对象所需的空间都从某个这样的内存池中开辟。在销毁对象时，只需要返回给该内存池。"一个类的所有对象都分配在同一个内存池对象中"这一需求很自然的设计方法就是为这样的类声明一个静态内存池对象，同时为了让其所有对象都从这个内存池中开辟内存，而不是缺省的从进程堆中获得，需要为该类重载一个new运算符。因为相应地，回收也是面向内存池，而不是进程的缺省堆，还需要重载一个delete运算符。在new运算符中用内存池的Alloc函数满足所有该类对象的内存请求，而销毁某对象则可以通过在 delete运算符中调用内存池的Free完成。</p>
<p><a name=N1031C><span class=smalltitle>6.2.5 性能比较</span></a></p>
<p>为了测试利用内存池后的效果，通过一个很小的测试程序可以发现采用内存池机制后耗时为297 ms。而没有采用内存池机制则耗时625 ms，速度提高了52.48%。速度提高的原因可以归结为几点，其一，除了偶尔的内存申请和销毁会导致从进程堆中分配和销毁内存块外，绝大多数的内存申请和销毁都由内存池在已经申请到的内存块中进行，而没有直接与进程堆打交道，而直接与进程堆打交道是很耗时的操作；其二，这是单线程环境的内存池，可以看到内存池的Alloc和Free操作中并没有加线程保护措施。因此如果类A用到该内存池，则所有类A对象的创建和销毁都必须发生在同一个线程中。但如果类A 用到内存池，类B也用到内存池，那么类A的使用线程可以不必与类B的使用线程是同一个线程。</p>
<p>另外，在第1章中已经讨论过，因为内存池技术使得同类型的对象分布在相邻的内存区域，而程序会经常对同一类型的对象进行遍历操作。因此在程序运行过程中发生的缺页应该会相应少一些，但这个一般只能在真实的复杂应用环境中进行验证。</p>
<div class=ibm-alternate-rule></div>
<p class="ibm-ind-link ibm-back-to-top"><a class=ibm-anchor-up-link href="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index6.html?ca=drs-cn#ibm-pcon"><u><font color=#0066cc>回页首</font></u></a></p>
<p><a name=N10328><span class=atitle>6.3 本章小结</span></a></p>
<p>内存的申请和释放对一个应用程序的整体性能影响极大，甚至在很多时候成为某个应用程序的瓶颈。消除内存申请和释放引起的瓶颈的方法往往是针对内存使用的实际情况提供一个合适的内存池。内存池之所以能够提高性能，主要是因为它能够利用应用程序的实际内存使用场景中的某些"特性"。比如某些内存申请与释放肯定发生在一个线程中，某种类型的对象生成和销毁与应用程序中的其他类型对象要频繁得多，等等。针对这些特性，可以为这些特殊的内存使用场景提供量身定做的内存池。这样能够消除系统提供的缺省内存机制中，对于该实际应用场景中的不必要的操作，从而提升应用程序的整体性能。</p>
<img src ="http://www.cppblog.com/guojingjia2006/aggbug/143473.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2011-04-05 20:18 <a href="http://www.cppblog.com/guojingjia2006/archive/2011/04/05/143473.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c++ 内存泄露(转)</title><link>http://www.cppblog.com/guojingjia2006/archive/2011/04/05/143472.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Tue, 05 Apr 2011 12:11:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2011/04/05/143472.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/143472.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2011/04/05/143472.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/143472.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/143472.html</trackback:ping><description><![CDATA[<p>&nbsp;内存泄露相信对C++程序员来说都不陌生。解决内存泄露的方案多种多样，大部分方案以追踪检测为主，这种方法实现起来容易，使用方便，也比较安全。</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;首先我们要确定这个模块的主要功能：</p>
<ol>
    <li>能追踪内存的分配和释放过程。</li>
    <li>要能显示内存分配的相关信息，比如内存块大小，代码所在文件所在行等。</li>
    <li>在发现内存泄露时及时给出相关信息。</li>
    <li>能正确处理一些异常情况，比如内存不足，对象初始化失败等等。</li>
    <li>是线程安全的。[*这个还没有实现]</li>
</ol>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;有了一些基本功能需求，我们需要考虑每种功能怎么去实现。首先，我们可以通过重载的方式来追踪new,delete.malloc和free，C++给我提供了这样的特性。因为本文主要针对C++，所以主要讲重载new,delete的方法，malloc和free的重载实现于此类似，最终版本的程序中也实现了malloc和free的重载。<a id=more></a></p>
<p><strong>1.重载new和delete</strong></p>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;首先我们要了解一下new和delete是怎么工作的。C++中的操作符最终都会被转换成函数形式，例如"new int"会变成"opetaor new(sizeof(int))"，而"new double[10]"会变成"operator new(sizeof(double)*10)"，同样&#8220;delete p&#8221;就变成了"operator delete(p)"。另外一个需要特别注意的地方是，new对于用户定义的数据类型（即你的自定义类）会自动调用该类型的构造函数，如果构造函数没有抛出异常，则正确分配，否则会中断分配操作，将异常传递给用户。默认情况下，new可以对象构造异常进行捕获。另外一个版本的new就是不带捕获异常功能的的了，所以C++系统提供的new和delete有：</p>
<div>
<div id=highlighter_657805 class="syntaxhighlighter  cpp">
<div class=toolbar><span><a class="toolbar_item command_help help" href="http://ofan.is-programmer.com/posts/16822.html#"><u><font color=#0066cc>?</font></u></a></span></div>
<table border=0 cellSpacing=0 cellPadding=0>
    <tbody>
        <tr>
            <td class=gutter>
            <div class="line number1 index0 alt2">1</div>
            <div class="line number2 index1 alt1">2</div>
            <div class="line number3 index2 alt2">3</div>
            <div class="line number4 index3 alt1">4</div>
            <div class="line number5 index4 alt2">5</div>
            <div class="line number6 index5 alt1">6</div>
            <div class="line number7 index6 alt2">7</div>
            <div class="line number8 index7 alt1">8</div>
            <div class="line number9 index8 alt2">9</div>
            </td>
            <td class=code>
            <div class=container>
            <div class="line number1 index0 alt2"><code class="cpp keyword bold">void</code><code class="cpp plain">* operator </code><code class="cpp keyword bold">new</code><code class="cpp plain">(</code><code class="cpp color1 bold">size_t</code> <code class="cpp plain">size)</code><code class="cpp keyword bold">throw</code><code class="cpp plain">(std::bad_alloc);</code></div>
            <div class="line number2 index1 alt1"><code class="cpp keyword bold">void</code><code class="cpp plain">* operator </code><code class="cpp keyword bold">new</code><code class="cpp plain">[](</code><code class="cpp color1 bold">size_t</code> <code class="cpp plain">size) </code><code class="cpp keyword bold">throw</code><code class="cpp plain">(std::bad_alloc);</code></div>
            <div class="line number3 index2 alt2"><code class="cpp keyword bold">void</code><code class="cpp plain">* operator </code><code class="cpp keyword bold">new</code><code class="cpp plain">(</code><code class="cpp color1 bold">size_t</code><code class="cpp plain">,std::nothrow_t&amp;)</code><code class="cpp keyword bold">throw</code><code class="cpp plain">();</code></div>
            <div class="line number4 index3 alt1"><code class="cpp keyword bold">void</code><code class="cpp plain">* operator </code><code class="cpp keyword bold">new</code><code class="cpp plain">[](</code><code class="cpp color1 bold">size_t</code><code class="cpp plain">,std::nothrow_t&amp;)</code><code class="cpp keyword bold">throw</code><code class="cpp plain">();</code></div>
            <div class="line number5 index4 alt2">&nbsp;</div>
            <div class="line number6 index5 alt1"><code class="cpp keyword bold">void</code>&nbsp; <code class="cpp plain">operator </code><code class="cpp keyword bold">delete</code><code class="cpp plain">(</code><code class="cpp keyword bold">void</code><code class="cpp plain">* pointer);</code></div>
            <div class="line number7 index6 alt2"><code class="cpp keyword bold">void</code>&nbsp; <code class="cpp plain">operator </code><code class="cpp keyword bold">delete</code><code class="cpp plain">[](</code><code class="cpp keyword bold">void</code><code class="cpp plain">* pointer);</code></div>
            <div class="line number8 index7 alt1"><code class="cpp keyword bold">void</code>&nbsp; <code class="cpp plain">operator </code><code class="cpp keyword bold">delete</code><code class="cpp plain">(</code><code class="cpp keyword bold">void</code><code class="cpp plain">* pointer,std::nothrow_t&amp;);</code></div>
            <div class="line number9 index8 alt2"><code class="cpp keyword bold">void</code>&nbsp; <code class="cpp plain">operator </code><code class="cpp keyword bold">delete</code><code class="cpp plain">[](</code><code class="cpp keyword bold">void</code><code class="cpp plain">* pointer,std::nothrow_t&amp;);&lt;br&gt;</code></div>
            </div>
            </td>
        </tr>
    </tbody>
</table>
</div>
</div>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;其中，nothrow_t是一个空结构体&#8220;struct nothrow_t{}"，它的一个实例就是nothrow，C++用它来区分可以捕获异常的new和不可捕获异常的new。我们不能直接修改内部函数的行为，但是我们可以重载它们。为了实现提供内存分配信息的功能，我们给重载的函数加上几个参数。得到以下函数：</p>
<div>
<div id=highlighter_193681 class="syntaxhighlighter  cpp">
<div class=toolbar><span><a class="toolbar_item command_help help" href="http://ofan.is-programmer.com/posts/16822.html#"><u><font color=#0066cc>?</font></u></a></span></div>
<table border=0 cellSpacing=0 cellPadding=0>
    <tbody>
        <tr>
            <td class=gutter>
            <div class="line number1 index0 alt2">1</div>
            <div class="line number2 index1 alt1">2</div>
            <div class="line number3 index2 alt2">3</div>
            <div class="line number4 index3 alt1">4</div>
            <div class="line number5 index4 alt2">5</div>
            <div class="line number6 index5 alt1">6</div>
            <div class="line number7 index6 alt2">7</div>
            <div class="line number8 index7 alt1">8</div>
            <div class="line number9 index8 alt2">9</div>
            <div class="line number10 index9 alt1">10</div>
            <div class="line number11 index10 alt2">11</div>
            <div class="line number12 index11 alt1">12</div>
            <div class="line number13 index12 alt2">13</div>
            <div class="line number14 index13 alt1">14</div>
            </td>
            <td class=code>
            <div class=container>
            <div class="line number1 index0 alt2"><code class="cpp keyword bold">void</code><code class="cpp plain">* operator </code><code class="cpp keyword bold">new</code><code class="cpp plain">(</code><code class="cpp color1 bold">size_t</code> <code class="cpp plain">size);</code></div>
            <div class="line number2 index1 alt1"><code class="cpp keyword bold">void</code><code class="cpp plain">* operator </code><code class="cpp keyword bold">new</code><code class="cpp plain">[](</code><code class="cpp color1 bold">size_t</code> <code class="cpp plain">size);</code></div>
            <div class="line number3 index2 alt2"><code class="cpp keyword bold">void</code><code class="cpp plain">* operator </code><code class="cpp keyword bold">new</code><code class="cpp plain">(</code><code class="cpp color1 bold">size_t</code><code class="cpp plain">,std::nothrow_t&amp;)</code><code class="cpp keyword bold">throw</code><code class="cpp plain">();</code></div>
            <div class="line number4 index3 alt1"><code class="cpp keyword bold">void</code><code class="cpp plain">* operator </code><code class="cpp keyword bold">new</code><code class="cpp plain">[](</code><code class="cpp color1 bold">size_t</code><code class="cpp plain">,std::nothrow_t&amp;)</code><code class="cpp keyword bold">throw</code><code class="cpp plain">();</code></div>
            <div class="line number5 index4 alt2"><code class="cpp keyword bold">void</code><code class="cpp plain">* operator </code><code class="cpp keyword bold">new</code><code class="cpp plain">(</code><code class="cpp color1 bold">size_t</code> <code class="cpp plain">size,</code><code class="cpp keyword bold">const</code> <code class="cpp color1 bold">char</code><code class="cpp plain">* file,</code><code class="cpp keyword bold">const</code> <code class="cpp color1 bold">char</code><code class="cpp plain">* func,</code><code class="cpp keyword bold">const</code> <code class="cpp color1 bold">int</code> <code class="cpp plain">line)</code><code class="cpp keyword bold">throw</code><code class="cpp plain">(std::bad_alloc);</code></div>
            <div class="line number6 index5 alt1"><code class="cpp keyword bold">void</code><code class="cpp plain">* operator </code><code class="cpp keyword bold">new</code><code class="cpp plain">[](</code><code class="cpp color1 bold">size_t</code> <code class="cpp plain">size,</code><code class="cpp keyword bold">const</code> <code class="cpp color1 bold">char</code><code class="cpp plain">* file,</code><code class="cpp keyword bold">const</code> <code class="cpp color1 bold">char</code><code class="cpp plain">* func,</code><code class="cpp keyword bold">const</code> <code class="cpp color1 bold">int</code> <code class="cpp plain">line) </code><code class="cpp keyword bold">throw</code><code class="cpp plain">(std::bad_alloc);</code></div>
            <div class="line number7 index6 alt2"><code class="cpp keyword bold">void</code><code class="cpp plain">* operator </code><code class="cpp keyword bold">delete</code><code class="cpp plain">(</code><code class="cpp keyword bold">void</code><code class="cpp plain">* pointer);</code></div>
            <div class="line number8 index7 alt1"><code class="cpp keyword bold">void</code><code class="cpp plain">* operator </code><code class="cpp keyword bold">delete</code><code class="cpp plain">[](</code><code class="cpp keyword bold">void</code><code class="cpp plain">* pointer);</code></div>
            <div class="line number9 index8 alt2"><code class="cpp comments">/*******Placement Delete********/</code></div>
            <div class="line number10 index9 alt1"><code class="cpp keyword bold">void</code>&nbsp; <code class="cpp plain">operator </code><code class="cpp keyword bold">delete</code><code class="cpp plain">(</code><code class="cpp keyword bold">void</code><code class="cpp plain">* pointer,</code><code class="cpp keyword bold">const</code> <code class="cpp color1 bold">char</code><code class="cpp plain">* file,</code><code class="cpp keyword bold">const</code> <code class="cpp color1 bold">char</code><code class="cpp plain">* func,</code><code class="cpp keyword bold">const</code> <code class="cpp color1 bold">int</code> <code class="cpp plain">line);</code></div>
            <div class="line number11 index10 alt2"><code class="cpp keyword bold">void</code>&nbsp; <code class="cpp plain">operator </code><code class="cpp keyword bold">delete</code><code class="cpp plain">[](</code><code class="cpp keyword bold">void</code><code class="cpp plain">* pointer,</code><code class="cpp keyword bold">const</code> <code class="cpp color1 bold">char</code><code class="cpp plain">* file,</code><code class="cpp keyword bold">const</code> <code class="cpp color1 bold">char</code><code class="cpp plain">* func,</code><code class="cpp keyword bold">const</code> <code class="cpp color1 bold">int</code> <code class="cpp plain">line);</code></div>
            <div class="line number12 index11 alt1"><code class="cpp keyword bold">void</code>&nbsp; <code class="cpp plain">operator </code><code class="cpp keyword bold">delete</code><code class="cpp plain">(</code><code class="cpp keyword bold">void</code><code class="cpp plain">* pointer,std::nothrow_t&amp;);</code></div>
            <div class="line number13 index12 alt2"><code class="cpp keyword bold">void</code>&nbsp; <code class="cpp plain">operator </code><code class="cpp keyword bold">delete</code><code class="cpp plain">[](</code><code class="cpp keyword bold">void</code><code class="cpp plain">* pointer,std::nothrow_t&amp;);</code></div>
            <div class="line number14 index13 alt1"><code class="cpp comments">/*******************************/</code></div>
            </div>
            </td>
        </tr>
    </tbody>
</table>
</div>
</div>
<p>&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;中间的几个函数，就是我们主要需要重载的函数，模块的大部分工作也都由着几个函数完成。这些函数参数中，file表示分配代码所在的文件名，func表示代码所在的函数名，line表示代码行号。这几个参数信息我们可以通过编译器预定义好的几个宏来获得：__FILE__,__FUNCTION__,__LINE__。也就是说可以将"new ..."替换成"new(__FILE__,__FUNCTION__,__LINE__) ..."，最终成为"operator new(sizeof(...),__FILE__,__FUNCTION__,__LINE__)"的形式，也就达到了我们的目的。关于 placement delete将在下面详细解释。</p>
<p><strong>2.空间分配</strong></p>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;接下来我们要考虑内存分配信息的组织问题了。我们先来了解一下编译器是怎么组织的。在大部分编译器中，new所分配的空间都要大于实际申请的空间，大出来的部分就是编译器定义的内存块的信息，包括了内存块的大小还有一些其他信息。如下图所示：</p>
<p><img style="WIDTH: 400px; HEIGHT: 127px; CURSOR: pointer" title=在新窗口打开 alt="" src="http://ofan.is-programmer.com/user_files/ofan/Image/ss.jpg" width=400 height=127></p>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;我们把包含内存分配信息的部分叫做cookie数据。为了方便，我们把cookie数据放在分配的内存的起始位置，之后紧接有效数据区。我们还需要把返回给调用者的指针和new分配的数据区联系起来，原本想用性能比较好的STL的map数据结构来储存这些数据，但是map内部同样也使用new来分配内存，所以如果直接使用map来储存，就会陷入死循环中。所以这里我们必须自己现实一个数据结构。我们可以对返回给调用者的地址进行Hash，得到hash 表中的地址，具有相同Hash值的数据我们用一个单向链表连接起来。最终的数据结构如下图所示：</p>
<p><img style="WIDTH: 400px; HEIGHT: 234px; CURSOR: pointer" title=在新窗口打开 alt="" src="http://i929.photobucket.com/albums/ad139/odayfans/blog/struct.jpg" width=400 height=234></p>
<p><strong>2.1.构造函数中的异常</strong></p>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;另外一个必须要注意的一点是，new操作符会先分配空间然后调用用户自定义类型的构造函数，如果构造函数抛出异常，需要用户手动释放已分配的内存。问题在于释放这样的内存不能用一般的delete操作符，可以用一个例子来说明：</p>
<div>
<div id=highlighter_89017 class="syntaxhighlighter  cpp">
<div class=toolbar><span><a class="toolbar_item command_help help" href="http://ofan.is-programmer.com/posts/16822.html#"><u><font color=#0066cc>?</font></u></a></span></div>
<table border=0 cellSpacing=0 cellPadding=0>
    <tbody>
        <tr>
            <td class=gutter>
            <div class="line number1 index0 alt2">1</div>
            <div class="line number2 index1 alt1">2</div>
            <div class="line number3 index2 alt2">3</div>
            <div class="line number4 index3 alt1">4</div>
            <div class="line number5 index4 alt2">5</div>
            <div class="line number6 index5 alt1">6</div>
            <div class="line number7 index6 alt2">7</div>
            <div class="line number8 index7 alt1">8</div>
            <div class="line number9 index8 alt2">9</div>
            <div class="line number10 index9 alt1">10</div>
            <div class="line number11 index10 alt2">11</div>
            <div class="line number12 index11 alt1">12</div>
            <div class="line number13 index12 alt2">13</div>
            <div class="line number14 index13 alt1">14</div>
            <div class="line number15 index14 alt2">15</div>
            <div class="line number16 index15 alt1">16</div>
            <div class="line number17 index16 alt2">17</div>
            <div class="line number18 index17 alt1">18</div>
            <div class="line number19 index18 alt2">19</div>
            <div class="line number20 index19 alt1">20</div>
            <div class="line number21 index20 alt2">21</div>
            <div class="line number22 index21 alt1">22</div>
            <div class="line number23 index22 alt2">23</div>
            <div class="line number24 index23 alt1">24</div>
            <div class="line number25 index24 alt2">25</div>
            <div class="line number26 index25 alt1">26</div>
            </td>
            <td class=code>
            <div class=container>
            <div class="line number1 index0 alt2"><code class="cpp preprocessor">#include &lt;stdio.h&gt;</code></div>
            <div class="line number2 index1 alt1"><code class="cpp preprocessor">#include &lt;stdexcept&gt;</code></div>
            <div class="line number3 index2 alt2">&nbsp;</div>
            <div class="line number4 index3 alt1"><code class="cpp keyword bold">void</code><code class="cpp plain">* operator </code><code class="cpp keyword bold">new</code><code class="cpp plain">(</code><code class="cpp color1 bold">size_t</code> <code class="cpp plain">size, </code><code class="cpp color1 bold">int</code> <code class="cpp plain">line) {</code></div>
            <div class="line number5 index4 alt2"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp functions bold">printf</code><code class="cpp plain">(</code><code class="cpp string">"Allocate %u bytes on line %d\\n"</code><code class="cpp plain">, size, line);</code></div>
            <div class="line number6 index5 alt1"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp keyword bold">return</code> <code class="cpp plain">operator </code><code class="cpp keyword bold">new</code><code class="cpp plain">(size);</code></div>
            <div class="line number7 index6 alt2"><code class="cpp plain">}</code></div>
            <div class="line number8 index7 alt1">&nbsp;</div>
            <div class="line number9 index8 alt2"><code class="cpp keyword bold">class</code> <code class="cpp plain">UserClass {</code></div>
            <div class="line number10 index9 alt1"><code class="cpp keyword bold">public</code><code class="cpp plain">:</code></div>
            <div class="line number11 index10 alt2"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp plain">UserClass(</code><code class="cpp color1 bold">int</code> <code class="cpp plain">n)</code><code class="cpp keyword bold">throw</code><code class="cpp plain">(){</code></div>
            <div class="line number12 index11 alt1"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp keyword bold">if</code><code class="cpp plain">(n&lt;=0){</code></div>
            <div class="line number13 index12 alt2"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp keyword bold">throw</code> <code class="cpp plain">std::runtime_error(</code><code class="cpp string">"n must be positive"</code><code class="cpp plain">);</code></div>
            <div class="line number14 index13 alt1"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp plain">}</code></div>
            <div class="line number15 index14 alt2"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp plain">}</code></div>
            <div class="line number16 index15 alt1"><code class="cpp plain">};</code></div>
            <div class="line number17 index16 alt2">&nbsp;</div>
            <div class="line number18 index17 alt1"><code class="cpp color1 bold">int</code> <code class="cpp plain">main(){</code></div>
            <div class="line number19 index18 alt2"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp keyword bold">try</code><code class="cpp plain">{</code></div>
            <div class="line number20 index19 alt1"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp plain">UserClass* myobj=</code><code class="cpp keyword bold">new</code><code class="cpp plain">(__LINE__) UserClass(-10);</code></div>
            <div class="line number21 index20 alt2"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp keyword bold">delete</code> <code class="cpp plain">myobj; </code><code class="cpp comments">//doesn't work if placement was not defined</code></div>
            <div class="line number22 index21 alt1"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp plain">} </code><code class="cpp keyword bold">catch</code><code class="cpp plain">(</code><code class="cpp keyword bold">const</code> <code class="cpp plain">std::runtime_error&amp; e) {</code></div>
            <div class="line number23 index22 alt2"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp functions bold">fprintf</code><code class="cpp plain">(stderr,</code><code class="cpp string">"Exception: %s\n"</code><code class="cpp plain">,e.what());</code></div>
            <div class="line number24 index23 alt1"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp plain">}</code></div>
            <div class="line number25 index24 alt2"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp keyword bold">return</code> <code class="cpp plain">0;</code></div>
            <div class="line number26 index25 alt1"><code class="cpp plain">}&lt;br&gt;</code></div>
            </div>
            </td>
        </tr>
    </tbody>
</table>
</div>
</div>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;这里，虽然在new过后试图使用delete释放已经分配的内存，但是实际上不会释放。也许你的编译器会给出这样一条消息：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8220;no matching operator delete found&#8221;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;为了正确处理这种情况，并给用户提供相关的信息，我们需要定义placement delete操作符。placement delete是C++98标准中才有的一个特性，所以对于某些老的编译器（大致可以认为是指那些98年以前编写的编译器）不支持这个特性。这需要在模块中添加宏定义让用户可以关闭placement delete的定义，以便模块能在较老的编译器上编译。以下就是需要定义的placement delete操作符：</p>
<div>
<div id=highlighter_153460 class="syntaxhighlighter  cpp">
<div class=toolbar><span><a class="toolbar_item command_help help" href="http://ofan.is-programmer.com/posts/16822.html#"><u><font color=#0066cc>?</font></u></a></span></div>
<table border=0 cellSpacing=0 cellPadding=0>
    <tbody>
        <tr>
            <td class=gutter>
            <div class="line number1 index0 alt2">1</div>
            <div class="line number2 index1 alt1">2</div>
            <div class="line number3 index2 alt2">3</div>
            <div class="line number4 index3 alt1">4</div>
            </td>
            <td class=code>
            <div class=container>
            <div class="line number1 index0 alt2"><code class="cpp keyword bold">void</code>&nbsp; <code class="cpp plain">operator </code><code class="cpp keyword bold">delete</code><code class="cpp plain">(</code><code class="cpp keyword bold">void</code><code class="cpp plain">* pointer,</code><code class="cpp keyword bold">const</code> <code class="cpp color1 bold">char</code><code class="cpp plain">* file,</code><code class="cpp keyword bold">const</code> <code class="cpp color1 bold">char</code><code class="cpp plain">* func,</code><code class="cpp keyword bold">const</code> <code class="cpp color1 bold">int</code> <code class="cpp plain">line);</code></div>
            <div class="line number2 index1 alt1"><code class="cpp keyword bold">void</code>&nbsp; <code class="cpp plain">operator </code><code class="cpp keyword bold">delete</code><code class="cpp plain">[](</code><code class="cpp keyword bold">void</code><code class="cpp plain">* pointer,</code><code class="cpp keyword bold">const</code> <code class="cpp color1 bold">char</code><code class="cpp plain">* file,</code><code class="cpp keyword bold">const</code> <code class="cpp color1 bold">char</code><code class="cpp plain">* func,</code><code class="cpp keyword bold">const</code> <code class="cpp color1 bold">int</code> <code class="cpp plain">line);</code></div>
            <div class="line number3 index2 alt2"><code class="cpp keyword bold">void</code>&nbsp; <code class="cpp plain">operator </code><code class="cpp keyword bold">delete</code><code class="cpp plain">(</code><code class="cpp keyword bold">void</code><code class="cpp plain">* pointer,std::nothrow_t&amp;);</code></div>
            <div class="line number4 index3 alt1"><code class="cpp keyword bold">void</code>&nbsp; <code class="cpp plain">operator </code><code class="cpp keyword bold">delete</code><code class="cpp plain">[](</code><code class="cpp keyword bold">void</code><code class="cpp plain">* pointer,std::nothrow_t&amp;);&lt;br&gt;</code></div>
            </div>
            </td>
        </tr>
    </tbody>
</table>
</div>
</div>
<p><strong>3.检查内存泄露</strong></p>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;有了上面的实现，我们可以方便的手动检测内存泄露。通过一个函数来实现，它会检索整个hash表，如果表不为空则存在内存泄露。</p>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;为了达到在最后程序退出时检查内存泄露的目的，我们需要在所有对象调用析构函数后进行内存泄露检测，这是因为某些用户类型在构造函数里调用new而在析构函数里调用delete。这样做能大大的减小误报的概率。而且因为对象的析构函数的调用往往在主函数main()执行结束之后进行，所以我们也不能直接在主函数里进行内存泄露检测。这里我们利用一个全局对象来实现这种检测。首先我们定义一个类：</p>
<div>
<div id=highlighter_112612 class="syntaxhighlighter  cpp">
<div class=toolbar><span><a class="toolbar_item command_help help" href="http://ofan.is-programmer.com/posts/16822.html#"><u><font color=#0066cc>?</font></u></a></span></div>
<table border=0 cellSpacing=0 cellPadding=0>
    <tbody>
        <tr>
            <td class=gutter>
            <div class="line number1 index0 alt2">1</div>
            <div class="line number2 index1 alt1">2</div>
            <div class="line number3 index2 alt2">3</div>
            <div class="line number4 index3 alt1">4</div>
            <div class="line number5 index4 alt2">5</div>
            <div class="line number6 index5 alt1">6</div>
            <div class="line number7 index6 alt2">7</div>
            <div class="line number8 index7 alt1">8</div>
            <div class="line number9 index8 alt2">9</div>
            <div class="line number10 index9 alt1">10</div>
            <div class="line number11 index10 alt2">11</div>
            </td>
            <td class=code>
            <div class=container>
            <div class="line number1 index0 alt2"><code class="cpp keyword bold">class</code> <code class="cpp plain">MemCheck{</code></div>
            <div class="line number2 index1 alt1"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp keyword bold">public</code><code class="cpp plain">:</code></div>
            <div class="line number3 index2 alt2"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp plain">MemCheck(){</code></div>
            <div class="line number4 index3 alt1"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp functions bold">memset</code><code class="cpp plain">(pTable,0,</code><code class="cpp keyword bold">sizeof</code><code class="cpp plain">(mc_block_node_t*) * MC_HASHTABLESIZE);</code></div>
            <div class="line number5 index4 alt2"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp plain">}</code></div>
            <div class="line number6 index5 alt1"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp plain">~MemCheck(){</code></div>
            <div class="line number7 index6 alt2"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp keyword bold">if</code><code class="cpp plain">(mc_checkmem()){</code></div>
            <div class="line number8 index7 alt1"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp functions bold">abort</code><code class="cpp plain">();</code></div>
            <div class="line number9 index8 alt2"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp plain">}</code></div>
            <div class="line number10 index9 alt1"><code class="cpp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="cpp plain">}</code></div>
            <div class="line number11 index10 alt2"><code class="cpp plain">};</code></div>
            </div>
            </td>
        </tr>
    </tbody>
</table>
</div>
</div>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;这里的构造函数初始化Hash表。析构函数检测内存泄露。然后定义一个MemCheck的全局静态对象，这样当程序运行之前会初始化hash表，程序退出时检测内存泄露。可是问题又来了，如果一个程序中有多个全局静态对象会怎样？不幸的是，对于全局静态对象的构造顺序和析构顺序是C++标准中的一个未定义问题，也就是说，这个顺序取决于编译器的具体实现。考虑，绝大多数平台使用VC和GCC编译器，我们可以针对这两种编译器来控制全局对象的构造和解析顺序。</p>
<div>
<div id=highlighter_198281 class="syntaxhighlighter  cpp">
<div class=toolbar><span><a class="toolbar_item command_help help" href="http://ofan.is-programmer.com/posts/16822.html#"><u><font color=#0066cc>?</font></u></a></span></div>
<table border=0 cellSpacing=0 cellPadding=0>
    <tbody>
        <tr>
            <td class=gutter>
            <div class="line number1 index0 alt2">1</div>
            <div class="line number2 index1 alt1">2</div>
            <div class="line number3 index2 alt2">3</div>
            <div class="line number4 index3 alt1">4</div>
            <div class="line number5 index4 alt2">5</div>
            <div class="line number6 index5 alt1">6</div>
            <div class="line number7 index6 alt2">7</div>
            <div class="line number8 index7 alt1">8</div>
            <div class="line number9 index8 alt2">9</div>
            </td>
            <td class=code>
            <div class=container>
            <div class="line number1 index0 alt2"><code class="cpp preprocessor">#ifdef _MSC_VER</code></div>
            <div class="line number2 index1 alt1"><code class="cpp preprocessor">#pragma init_seg(lib)</code></div>
            <div class="line number3 index2 alt2"><code class="cpp preprocessor">#endif</code></div>
            <div class="line number4 index3 alt1">&nbsp;</div>
            <div class="line number5 index4 alt2"><code class="cpp keyword bold">static</code> <code class="cpp plain">MemCheck mc_autocheck_object</code></div>
            <div class="line number6 index5 alt1"><code class="cpp preprocessor">#ifdef __GNUC__</code></div>
            <div class="line number7 index6 alt2"><code class="cpp plain">__attribute__((init_priority (101)))</code></div>
            <div class="line number8 index7 alt1"><code class="cpp preprocessor">#endif</code></div>
            <div class="line number9 index8 alt2"><code class="cpp plain">;</code></div>
            </div>
            </td>
        </tr>
    </tbody>
</table>
</div>
</div>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;这里的宏定义部分都是编译器的选项。</p>
<img src ="http://www.cppblog.com/guojingjia2006/aggbug/143472.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2011-04-05 20:11 <a href="http://www.cppblog.com/guojingjia2006/archive/2011/04/05/143472.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>PE学习总结</title><link>http://www.cppblog.com/guojingjia2006/archive/2010/10/12/129621.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Tue, 12 Oct 2010 09:22:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2010/10/12/129621.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/129621.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2010/10/12/129621.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/129621.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/129621.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->#include&nbsp;"windows.h"#include&nbsp;&lt;iostream&gt;using&nbsp;namespace&nbsp;std;#define&nbsp;NTSI...&nbsp;&nbsp;<a href='http://www.cppblog.com/guojingjia2006/archive/2010/10/12/129621.html'>阅读全文</a><img src ="http://www.cppblog.com/guojingjia2006/aggbug/129621.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2010-10-12 17:22 <a href="http://www.cppblog.com/guojingjia2006/archive/2010/10/12/129621.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>__type_traits(转)</title><link>http://www.cppblog.com/guojingjia2006/archive/2010/10/11/129405.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Mon, 11 Oct 2010 01:24:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2010/10/11/129405.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/129405.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2010/10/11/129405.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/129405.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/129405.html</trackback:ping><description><![CDATA[<p><strong>在STL中为了提供通用的操作而又不损失效率，我们用到了一种特殊的技巧，叫traits编程技巧。具体的来说，traits就是
通过定义一些结构体或类，并利用模板类特化和偏特化的能力，给类型赋予一些特性，这些特性根据类型的不同而异。在程序设计中可以使用这些traits来判
断一个类型的一些特性，引发C++的函数重载机制，实现同一种操作因类型不同而异的效果。traits的编程技巧极度弥补了C++语言的不足 。</strong></p>
<p><br>
举例：<br>
<br>
现在定义一个__type_traits可以获得类型的如下属性：<br>
1. 是否存在non-trivial default constructor <br>
2. 是否存在non-trivial copy constructor<br>
3. 是否存在non-trivial assignment operator<br>
4. 是否存在non-trivial destructor<br>
<br>
<font color="#0000ff">struct __true_type {<br>
};<br>
struct __false_type {<br>
};<br>
<br>
template &lt;class _Tp&gt;<br>
struct __type_traits {</font></p>
<p><font color="#0000ff">&nbsp;&nbsp;  typedef __false_type&nbsp;&nbsp;&nbsp;  has_trivial_default_constructor;<br>
&nbsp;&nbsp;  typedef __false_type&nbsp;&nbsp;&nbsp;  has_trivial_copy_constructor;<br>
&nbsp;&nbsp;  typedef __false_type&nbsp;&nbsp;&nbsp;  has_trivial_assignment_operator;<br>
&nbsp;&nbsp;  typedef __false_type&nbsp;&nbsp;&nbsp;  has_trivial_destructor;<br>
};</font><br>
<br>
问题：为什么把对象的所有的属性都定义为__false_type？<br>
这样是采用最保守的做法，先把所有的对象属性都设置为__false_type，然后在针对每个基本数据类型设计特化的__type_traits，就可以达到预期的目的，如可以定义__type_traits&lt;int&gt;如下：<br>
<br>
<font color="#0000ff">template &lt;&gt;<br>
struct __type_traits&lt;int&gt; {<br>
&nbsp;&nbsp;  typedef __true_type&nbsp;&nbsp;&nbsp;  has_trivial_default_constructor;<br>
&nbsp;&nbsp;  typedef __true_type&nbsp;&nbsp;&nbsp;  has_trivial_copy_constructor;<br>
&nbsp;&nbsp;  typedef __true_type&nbsp;&nbsp;&nbsp;  has_trivial_assignment_operator;<br>
&nbsp;&nbsp;  typedef __true_type&nbsp;&nbsp;&nbsp;  has_trivial_destructor;<br>
};<br>
<br>
template &lt;&gt;<br>
struct __type_traits&lt;char&gt; {<br>
&nbsp;&nbsp;  typedef __true_type&nbsp;&nbsp;&nbsp;  has_trivial_default_constructor;<br>
&nbsp;&nbsp;  typedef __true_type&nbsp;&nbsp;&nbsp;  has_trivial_copy_constructor;<br>
&nbsp;&nbsp;  typedef __true_type&nbsp;&nbsp;&nbsp;  has_trivial_assignment_operator;<br>
&nbsp;&nbsp;  typedef __true_type&nbsp;&nbsp;&nbsp;  has_trivial_destructor;<br>
};<br>
<br>
&nbsp;&nbsp;&nbsp;  ......<br>
<br>
&nbsp;&nbsp;&nbsp;  ......</font><br>
<br>
其他基本类型的traits也可以有相应的定义<br>
<br>
__type_traits的偏特化版本<br>
<font color="#0000ff">template &lt;class _Tp&gt;<br>
struct __type_traits&lt;_Tp*&gt; {<br>
&nbsp;&nbsp;  typedef __true_type&nbsp;&nbsp;&nbsp;  has_trivial_default_constructor;<br>
&nbsp;&nbsp;  typedef __true_type&nbsp;&nbsp;&nbsp;  has_trivial_copy_constructor;<br>
&nbsp;&nbsp;  typedef __true_type&nbsp;&nbsp;&nbsp;  has_trivial_assignment_operator;<br>
&nbsp;&nbsp;  typedef __true_type&nbsp;&nbsp;&nbsp;  has_trivial_destructor;<br>
&nbsp;&nbsp;  typedef __true_type&nbsp;&nbsp;&nbsp;  is_POD_type;<br>
};<br>
</font><br>
我们可以自定义__type_traits的特化版本<br>
比如对与自定义的Shape类型，我们可以这样定义__type_traits&lt;Shape&gt;<br>
<font color="#0000ff">struct __type_traits&lt;Shape&gt; {<br>
&nbsp;&nbsp;  typedef __false_type&nbsp;&nbsp;&nbsp;  has_trivial_default_constructor;<br>
&nbsp;&nbsp;  typedef __true_type&nbsp;&nbsp;&nbsp;  has_trivial_copy_constructor;<br>
&nbsp;&nbsp;  typedef __true_type&nbsp;&nbsp;&nbsp;  has_trivial_assignment_operator;<br>
&nbsp;&nbsp;  typedef __true_type&nbsp;&nbsp;&nbsp;  has_trivial_destructor;<br>
&nbsp;&nbsp;  typedef __true_type&nbsp;&nbsp;&nbsp;  is_POD_type;<br>
};<br>
</font><br>
如果编译器够厉害，我们甚至可以不用自己去定义特化的__type_traits，编译器就能够帮我们搞定：）<br>
<br>
如何使用呢？<br>
<br>
假设现在用个模板函数fun需要根据类型T是否有non-trivial constructor来进行不同的操作，可以这样来实现：<br>
<br>
<font color="#0000ff">template&lt;class T&gt;<br>
void fun()<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;  typedef typename __type_traits&lt;T&gt;::has_trivial_constructor _Trivial_constructor;<br>
&nbsp;&nbsp;&nbsp;  __fun(_Trivial_constructor()); // 根据得到的_Trivial_constructor来调用相应的函数<br>
}<br>
</font><br>
<font color="#0000ff">// 两个重载的函数<br>
void _fun(_true_type)<br>
{<br>
cout&lt;&lt;"fun(_true_type)called"&lt;&lt;endl;<br>
}<br>
void _fun(_false_type)<br>
{<br>
cout&lt;&lt;"fun(_false_type) called"&lt;&lt;endl;<br>
}</font></p>
<p><font color="#0000ff">//测试代码</font></p>
<p><font color="#0000ff">int main()<br>
{<br>
fun&lt;char&gt;();<br>
fun&lt;int&gt;();<br>
fun&lt;char *&gt;();<br>
fun&lt;double&gt;();<br>
}</font></p><img src ="http://www.cppblog.com/guojingjia2006/aggbug/129405.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2010-10-11 09:24 <a href="http://www.cppblog.com/guojingjia2006/archive/2010/10/11/129405.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Traits学习--迭代器(1)</title><link>http://www.cppblog.com/guojingjia2006/archive/2010/10/09/129184.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Sat, 09 Oct 2010 05:23:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2010/10/09/129184.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/129184.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2010/10/09/129184.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/129184.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/129184.html</trackback:ping><description><![CDATA[<br>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; font-family: courier new;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->用template要求写一个模板函数，返回值要求是参数类型，初步设计<br><span style="color: #000000;">template</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">typename&nbsp;T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;AIter{<br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">:<br>&nbsp;&nbsp;&nbsp;&nbsp;AIter(T</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;p</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">):ptr(p){};<br>&nbsp;&nbsp;&nbsp;&nbsp;T</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;ptr;<br>&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;T&nbsp;value_type;<br>&nbsp;&nbsp;&nbsp;&nbsp;T</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">operator</span><span style="color: #000000;">*</span><span style="color: #000000;">()</span><span style="color: #0000ff;">const</span><span style="color: #000000;">{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">ptr;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;T</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">operator</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">()</span><span style="color: #0000ff;">const</span><span style="color: #000000;">{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;ptr;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>};<br>template</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">typename&nbsp;T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br>typename&nbsp;T::value_type<br>func(T&nbsp;val){<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">val;<br>}<br><br>这方法一个缺陷就是对于不是class type的类型无能为力,比如原生指针,只有class type类型才能内嵌类型<br><br>改进--模板偏特化(template partial specialization)<br>声明一个类型<br>template&lt;typename T&gt;<br>struct stl_iterator_traits{<br>&nbsp;&nbsp;&nbsp; typedef typename T::value_type value_type;<br>};<br>原先的func可以写成这样<br>template&lt;typename T&gt;<br>typename stl_iterator_traits&lt;T&gt;::value_type<br>func(T val){<br>&nbsp;&nbsp;&nbsp; return *val;<br>}<br>这样还是处理不了<br>int* p=new int(3);<br>func(p);<br>原生指针类型，为其提供特化版本<br>template&lt;typename T&gt;<br>struct stl_iterator_traits&lt;T*&gt;{<br>&nbsp;&nbsp;&nbsp; typedef T value_type;<br>};<br>这样就能完美解决刚才问题<br><br>但是对于指向常数对象的指针<br>stl_iterator_traits&lt;const int*&gt;::value_type<br>我们希望暂时存储一个变量，但是我们获取的类型是const int,声明一个无法赋值的临时变量无意义，所以我们在提供一个特化版本<br></span><span style="color: #000000;">template&lt;typename T&gt;<br>
struct stl_iterator_traits&lt;const T*&gt;{<br>
&nbsp;&nbsp;&nbsp; typedef T value_type;<br>
};<br>iterator example:<br></span>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">iterator</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #008000;">//</span><span style="color: #008000;">#using&nbsp;&lt;mscorlib.dll&gt;</span><span style="color: #008000;"><br></span><span style="color: #000000;">#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">iostream</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br>#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">memory</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br>#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">vector</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br>#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">algorithm</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #008000;">//</span><span style="color: #008000;">using&nbsp;namespace&nbsp;System;</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">using</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">namespace</span><span style="color: #000000;">&nbsp;std;<br><br>template</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">typename&nbsp;T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;ListItem{<br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">:<br>&nbsp;&nbsp;&nbsp;&nbsp;ListItem(T&nbsp;value){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_value</span><span style="color: #000000;">=</span><span style="color: #000000;">value;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_next</span><span style="color: #000000;">=</span><span style="color: #000000;">NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;ListItem(){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_next</span><span style="color: #000000;">=</span><span style="color: #000000;">NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_value</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;T&nbsp;value()</span><span style="color: #0000ff;">const</span><span style="color: #000000;">{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;_value;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;ListItem</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">T</span><span style="color: #000000;">&gt;*</span><span style="color: #000000;">&nbsp;_next;<br>&nbsp;&nbsp;&nbsp;&nbsp;T&nbsp;_value;&nbsp;&nbsp;&nbsp;&nbsp;<br>};<br>template</span><span style="color: #000000;">&lt;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Item</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;ListIter:</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;iterator</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">std::forward_iterator_tag,Item</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">{<br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">:<br>&nbsp;&nbsp;&nbsp;&nbsp;Item</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;ptr;<br>&nbsp;&nbsp;&nbsp;&nbsp;ListIter(Item</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;p</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">):ptr(p){};<br>&nbsp;&nbsp;&nbsp;&nbsp;Item</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">operator</span><span style="color: #000000;">*</span><span style="color: #000000;">()</span><span style="color: #0000ff;">const</span><span style="color: #000000;">{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">ptr;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;Item</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">operator</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">()</span><span style="color: #0000ff;">const</span><span style="color: #000000;">{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;ptr;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;ListIter</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">operator</span><span style="color: #000000;">++</span><span style="color: #000000;">(){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ptr</span><span style="color: #000000;">=</span><span style="color: #000000;">ptr</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">_next;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #0000ff;">this</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;ListIter&nbsp;</span><span style="color: #0000ff;">operator</span><span style="color: #000000;">++</span><span style="color: #000000;">(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ListIter&nbsp;tmp</span><span style="color: #000000;">=*</span><span style="color: #0000ff;">this</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">++</span><span style="color: #000000;">(</span><span style="color: #000000;">*</span><span style="color: #0000ff;">this</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;tmp;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">bool</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">operator</span><span style="color: #000000;">==</span><span style="color: #000000;">(</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;ListIter</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;iter)</span><span style="color: #0000ff;">const</span><span style="color: #000000;">{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;ptr</span><span style="color: #000000;">==</span><span style="color: #000000;">iter.ptr;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">bool</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">operator</span><span style="color: #000000;">!=</span><span style="color: #000000;">(</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;ListIter</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;iter)</span><span style="color: #0000ff;">const</span><span style="color: #000000;">{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;ptr</span><span style="color: #000000;">!=</span><span style="color: #000000;">iter.ptr;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>};<br>template</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">typename&nbsp;T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">bool</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">operator</span><span style="color: #000000;">==</span><span style="color: #000000;">(ListItem</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">T</span><span style="color: #000000;">&gt;&amp;</span><span style="color: #000000;">&nbsp;item,T&nbsp;value){<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;item.value()</span><span style="color: #000000;">==</span><span style="color: #000000;">value;<br>}<br><br>template</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">typename&nbsp;T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;List{<br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">:<br>&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;ListIter</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">ListItem</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;iterator;<br>&nbsp;&nbsp;&nbsp;&nbsp;List(){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_end</span><span style="color: #000000;">=</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;ListItem</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_front</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;insert_front(T&nbsp;value){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ListItem</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">T</span><span style="color: #000000;">&gt;*</span><span style="color: #000000;">&nbsp;item</span><span style="color: #000000;">=</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;ListItem</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">(value);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(empty()){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">_next</span><span style="color: #000000;">=</span><span style="color: #000000;">_end;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_front</span><span style="color: #000000;">=</span><span style="color: #000000;">item;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><span style="color: #0000ff;">else</span><span style="color: #000000;">{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">_next</span><span style="color: #000000;">=</span><span style="color: #000000;">_front;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_front</span><span style="color: #000000;">=</span><span style="color: #000000;">item;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;};<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">bool</span><span style="color: #000000;">&nbsp;empty(){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;_front</span><span style="color: #000000;">==</span><span style="color: #000000;">NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;insert_end(T&nbsp;value){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">ListItem&lt;T&gt;*&nbsp;item=new&nbsp;ListItem&lt;T&gt;(value);</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(empty()){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_front</span><span style="color: #000000;">=</span><span style="color: #000000;">_end;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_end</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">_value</span><span style="color: #000000;">=</span><span style="color: #000000;">value;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_end</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">_next</span><span style="color: #000000;">=</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;ListItem</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_end</span><span style="color: #000000;">=</span><span style="color: #000000;">_end</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">_next;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><span style="color: #0000ff;">else</span><span style="color: #000000;">{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_end</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">_value</span><span style="color: #000000;">=</span><span style="color: #000000;">value;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_end</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">_next</span><span style="color: #000000;">=</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;ListItem</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_end</span><span style="color: #000000;">=</span><span style="color: #000000;">_end</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">_next;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;};<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;display(ostream</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;os</span><span style="color: #000000;">=</span><span style="color: #000000;">cout){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ListItem</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">T</span><span style="color: #000000;">&gt;*</span><span style="color: #000000;">&nbsp;head</span><span style="color: #000000;">=</span><span style="color: #000000;">_front;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">(head</span><span style="color: #000000;">!=</span><span style="color: #000000;">_end){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">head</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">value()</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;head</span><span style="color: #000000;">=</span><span style="color: #000000;">head</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">_next;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;};<br>&nbsp;&nbsp;&nbsp;&nbsp;ListItem</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">T</span><span style="color: #000000;">&gt;*</span><span style="color: #000000;">&nbsp;front(){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;_front;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="color: #0000ff;">private</span><span style="color: #000000;">:<br>&nbsp;&nbsp;&nbsp;&nbsp;ListItem</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">T</span><span style="color: #000000;">&gt;*</span><span style="color: #000000;">&nbsp;_end;<br>&nbsp;&nbsp;&nbsp;&nbsp;ListItem</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">T</span><span style="color: #000000;">&gt;*</span><span style="color: #000000;">&nbsp;_front;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">long</span><span style="color: #000000;">&nbsp;_size;<br>};<br><br>template</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">typename&nbsp;T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">struct</span><span style="color: #000000;">&nbsp;stl_iterator_traits{<br>&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;typename&nbsp;T::value_type&nbsp;value_type;<br>};<br><br>template</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">typename&nbsp;T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">struct</span><span style="color: #000000;">&nbsp;stl_iterator_traits</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">T</span><span style="color: #000000;">*&gt;</span><span style="color: #000000;">{<br>&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;T&nbsp;value_type;<br>};<br><br>template</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">typename&nbsp;T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;AIter{<br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">:<br>&nbsp;&nbsp;&nbsp;&nbsp;AIter(T</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;p</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">):ptr(p){};<br>&nbsp;&nbsp;&nbsp;&nbsp;T</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;ptr;<br>&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;T&nbsp;value_type;<br>&nbsp;&nbsp;&nbsp;&nbsp;T</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">operator</span><span style="color: #000000;">*</span><span style="color: #000000;">()</span><span style="color: #0000ff;">const</span><span style="color: #000000;">{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">ptr;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;T</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">operator</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">()</span><span style="color: #0000ff;">const</span><span style="color: #000000;">{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;ptr;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>};<br>template</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">typename&nbsp;T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br>typename&nbsp;stl_iterator_traits</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">::value_type<br>func(T&nbsp;val){<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">val;<br>}<br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;_tmain(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;argc,&nbsp;_TCHAR</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;argv[])<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;List</span><span style="color: #000000;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;list;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;i</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">;i</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">5</span><span style="color: #000000;">;i</span><span style="color: #000000;">++</span><span style="color: #000000;">){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list.insert_front(i);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list.insert_end(i</span><span style="color: #000000;">+</span><span style="color: #000000;">2</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;list.display();<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;List</span><span style="color: #000000;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">::iterator&nbsp;begin(list.front());<br>&nbsp;&nbsp;&nbsp;&nbsp;List</span><span style="color: #000000;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">::iterator&nbsp;end;<br>&nbsp;&nbsp;&nbsp;&nbsp;List</span><span style="color: #000000;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">::iterator&nbsp;iter;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">vector&lt;int&gt;::iterator&nbsp;itere;</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;AIter</span><span style="color: #000000;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;it(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">(</span><span style="color: #000000;">2</span><span style="color: #000000;">));<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;iter</span><span style="color: #000000;">=</span><span style="color: #000000;">find(begin,end,</span><span style="color: #000000;">2</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">iter</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">value()</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">list.insert_end(1);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">list.insert_end(2);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">list.display();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">list.insert_end(</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>}<br></span></div>
<br>现在对于class type 迭代器AIter,还是原生指针int* 或const int*,都能获取正确类型int<br>stl规定，每个迭代器都要自己内嵌型别定义的方式定义出相应型别<br>(待续...)<br></div><img src ="http://www.cppblog.com/guojingjia2006/aggbug/129184.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2010-10-09 13:23 <a href="http://www.cppblog.com/guojingjia2006/archive/2010/10/09/129184.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> Effective C++连载(转)</title><link>http://www.cppblog.com/guojingjia2006/archive/2010/10/08/129008.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Fri, 08 Oct 2010 01:19:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2010/10/08/129008.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/129008.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2010/10/08/129008.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/129008.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/129008.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 第一章 从C转向C++对每个人来说，习惯C++需要一些时间，对于已经熟悉C的程序员来说，这个过程尤其令人苦恼。因为C是C++的子集，所有的C的技术都可以继续使用，但很多用起来又不太合适。例如，C++程序员会认为指针的指针看起来很古怪，他们会问：为什么不用指针的引用来代替呢？C是一种简单的语言。它真正提供的只有有宏、指针、结构、数组和函数。不管什么问题，C都靠宏、指针、结构、数组和函数来解决...&nbsp;&nbsp;<a href='http://www.cppblog.com/guojingjia2006/archive/2010/10/08/129008.html'>阅读全文</a><img src ="http://www.cppblog.com/guojingjia2006/aggbug/129008.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2010-10-08 09:19 <a href="http://www.cppblog.com/guojingjia2006/archive/2010/10/08/129008.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>