??xml version="1.0" encoding="utf-8" standalone="yes"?>久久国产精品-久久精品,国产午夜精品久久久久九九电影 ,久久久久国产亚洲AV麻豆http://www.shnenglu.com/guojingjia2006/category/14893.htmlPay it forword - 我ƈ不觉的自豪,我所试的事情都p|了······习惯原本生zȝZҎ改变Q就现状很p,他们也很难改变,在过E中Q他们还是放弃了······他们一攑ּQ大家就都是输家······让爱传出去,很困难,也无法预料,Z需要更l心的观察别人,要随时注意才能保护别人,因ؓ他们未必知道自己要什么····?/description>zh-cnFri, 11 Jan 2013 11:21:12 GMTFri, 11 Jan 2013 11:21:12 GMT60Centos~译boosthttp://www.shnenglu.com/guojingjia2006/archive/2013/01/07/197075.html果?/dc:creator>果?/author>Mon, 07 Jan 2013 08:38:00 GMThttp://www.shnenglu.com/guojingjia2006/archive/2013/01/07/197075.htmlhttp://www.shnenglu.com/guojingjia2006/comments/197075.htmlhttp://www.shnenglu.com/guojingjia2006/archive/2013/01/07/197075.html#Feedback0http://www.shnenglu.com/guojingjia2006/comments/commentRss/197075.htmlhttp://www.shnenglu.com/guojingjia2006/services/trackbacks/197075.htmlhttp://blog.sina.com.cn/s/blog_6f2caee40100uhj6.html
1.下蝲最新的boost
http://www.boost.org/
2.解压文g
tar -xzvf boost_1_45_0.tar.gz 
3.~译bjam
q入boost_1_45_0目录中,q行./bootstrap.shQ完成后会得C个bjam
4.~译boost 
./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
5.查看boost
~译完成后,?usr/local/include/boost有最新的boost头文件了Q在/usr/local/lib有~译好的.a库文件了?/div>
虽然usr/local/include?usr/include都有目录Q但GCC是先讉K/usr/local/includeQ所以编译完成后Q就可以默认使用boost了?/div>
6.试boost
vi testboost.cpp
#include <iostream>
#include <boost/version.hpp>
int main()
{
    std::cout<<BOOST_VERSION<<std::endl;
    return 0;
}
~译:g++ -o testboost testboost.cpp


]]>mint 下codeblocks ~译libapue http://www.shnenglu.com/guojingjia2006/archive/2013/01/04/196955.html果?/dc:creator>果?/author>Fri, 04 Jan 2013 12:23:00 GMThttp://www.shnenglu.com/guojingjia2006/archive/2013/01/04/196955.htmlhttp://www.shnenglu.com/guojingjia2006/comments/196955.htmlhttp://www.shnenglu.com/guojingjia2006/archive/2013/01/04/196955.html#Feedback0http://www.shnenglu.com/guojingjia2006/comments/commentRss/196955.htmlhttp://www.shnenglu.com/guojingjia2006/services/trackbacks/196955.html于是乎下了一个,׃是乎惛_几个sample玩玩。于是乎?lt;unix 高环境~程> sample来测试?br />
于是乎徏了一个c++ project.
<unix 高环境~程>里的例子有个apue.h头文件。不是系l自带的。是作者自己写的几个util函数?br />|上扄译apue.h头文件一大片。但是都是考来考去Q不q核心的都差不多。不q有个方法是~译?br />libapue.a静态库后,q需要在apute.h头文件尾巴加"error.c"。。完了拷贝error.c实现到目录。?br />看完后。我惊了呆。。好吧。。这库还能这么用。?br />
既然libapue.a~译完后Qapue.h里的函数声明在libapue.a都已l实玎ͼ当然包括err_xxxpd的。所?br />在apue.h?error.c"是画蛇添뀂。这里不推荐此方法。?br />
我的环境是mint14? IDE用的?codeblocks. Ҏ中基本都有这么一个步骤:
先在q个|站 http://www.apuebook.com/src.tar.gz 下蝲tar.gz格式的源码包Q然后解压至某个目录Q比如说/home/xiaoguozi/下,然后q入目录apue.2eQ把文g Make.defines.linux 中的 WKDIR=/home/xxx/apue.2e 修改? WKDIR=/home/xiaoguozi/apue.2e Q然后再q入apue.2e目录下的std目录Q打开linux.mkQ将里面的nawk全部替换为awk
如果用vim~辑的话Q可以用 :1,%s/nawk/awk/g 替换字符H?br />
完了make, q程中,q遇C几个问题?mint?其他os不太清楚)

1: /usr/include/bits/timex.h:31:7:error: expect ':' , ',' , ';' , '}' or '__attribute__'   
 apue.2e/ipp/ipp.h?#define status u.st ?timex.h中的 status 冲突Q更?#define Status u.st

  

2QARG_MAX 未定?/span>

   在include/apue.h中加?#define ARG_MAX 4096

   在threadctl/getenv1.c 加入 #include "../include/apue.h"

   在threadctl/getenv3.c 加入 #include "../include/apue.h"

完了之后Qmake应该可以成功了

完了在codeblocks目里引用刚~译完的库,有几个方?
1)编译完的库,头文件apue.h拯/usr/include,库文件libapue.a拯?usr/lib下,q个是系l目录,gcc~译的时候会在这目录搜寻
2)在项目属性添加静态库引用
d头文Ӟ依次点击project->bulid options->Search directoriesQ在该标{N中点击CompilerQ单击Add按钮d头文件\?br />d静态库路径Q依ơ点击project->bulid options->Linker settingQ在该标{N中点击Add按钮d静态库路径?br />
如果之前你徏的是c project的话Q应该就可以利~译通过了,但是对于建立c++的project,仍然提示链接错误Q找不到函数实现Q?br />原因是libapue.a是c库,用g++~译的时候要引用c库的话,因ؓc++~译的时候会在函数加一些额外字W,所以当然会链接错误?/div>
解决也简单的在函数库前加 extern "C",或者直接把apue.h用extern "C"包含Q不清楚的补下相应知识?br />
加点额外的知识关于gcc/g++Q?br />
gcc和g++的区?p>误区一:gcc只能~译c代码,g++只能~译c++代码
两者都可以Q但是请注意Q?br />1.后缀?c的,gcc把它当作是CE序Q而g++当作是c++E序Q后~?cpp的,两者都会认为是c++E序Q注意,虽然c++是c的超集,但是两者对语法的要求是有区别的。C++的语法规则更加严谨一些?br />2.~译阶段Qg++会调用gccQ对于c++代码Q两者是{h的,但是因ؓgcc命o不能自动和CQ+E序使用的库联接Q所以通常用g++来完成链接,Zl一赯Q干脆编?链接l统用g++了,q就lh一U错觉,好像cppE序只能用g++似的?br />
误区?gcc不会定义__cplusplus宏,而g++?br />实际上,q个宏只是标志着~译器将会把代码按Cq是C++语法来解释,如上所qͼ如果后缀?cQƈ且采用gcc~译器,则该宏就是未定义的,否则Q就是已定义?br />
误区?~译只能用gccQ链接只能用g++
严格来说Q这句话不算错误Q但是它h了概念,应该q样_~译可以用gcc/g++Q而链接可以用g++或者gcc -lstdc++。因为gcc命o不能自动和CQ+E序使用的库联接Q所以通常使用g++来完成联接。但在编译阶D,g++会自动调用gccQ二者等仗?/p> gcc和g++的区? 我们在编译c/c++代码的时候,有h用gccQ有人用g++Q于是各U说法都来了Q譬如c代码用gccQ而c++代码用g++Q或者说~译? gccQ链接用g++Q一时也不知哪个说法正确Q如果再遇上个extern "C"Q分歧就更多了,q里我想作个了结Q毕竟知识的目的是o人更清醒Q而不是更p涂?/div>



]]>Installing Gearman and gearmand on Windows with Cygwin http://www.shnenglu.com/guojingjia2006/archive/2012/12/28/196743.html果?/dc:creator>果?/author>Fri, 28 Dec 2012 03:17:00 GMThttp://www.shnenglu.com/guojingjia2006/archive/2012/12/28/196743.htmlhttp://www.shnenglu.com/guojingjia2006/comments/196743.htmlhttp://www.shnenglu.com/guojingjia2006/archive/2012/12/28/196743.html#Feedback0http://www.shnenglu.com/guojingjia2006/comments/commentRss/196743.htmlhttp://www.shnenglu.com/guojingjia2006/services/trackbacks/196743.html

Recently I've come face-to-face with a significant processing task for a web application written in PHP.  I haven't worked with process control very much, so I started researching ways of distributing the calculations to multiple processes.  PHP offers several libraries for doing this (pcntl, POSIX), 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.  After a lot more research, I came across Gearman.

Gearman is essentially a distributed processing framework, and seems to have community support for many programming languages.  It consists of two main components: the job server, and a Client and Worker API.  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.  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.  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.

Nonetheless, after yet more research I decided that I would give it a shot by using Cygwin 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.  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.

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.  I used a Windows XP SP3 machine for this, but I also got it working on a Windows 7 machine as well.

Installing the Gearman job server (gearmand) on Windows with Cygwin

Installing Cygwin

  1. If you don't have Cygwin already, you can get it from http://www.cygwin.com.  The setup file is located here, and the setup process is pretty straightforward; run it and follow the wizard.  Full installation instructions are available at the Cygwin site.
  2. 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.
  3. Cygwin installs with some basic packages, including a Cygwin Bash Shell that goes into your Start Menu.  I prefer the mintty emulator instead, as it has less of a DOS Command Prompt feel and better terminal features.  Feel free to use whatever shell you like of course.  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.  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.

Installing Cygwin Package Dependencies needed for Gearman

If you're not already in the Cygwin setup, re-run the Cygwin setup.exe and go through to the package selection screen.  The following is a list of dependency packages you will need in order to build the Gearman job server (gearmand).  None of these packages were installed by default with Cygwin:

  • gcc
  • make
  • libuuid1-devel
  • libiconv

There's a good installation tutorial here that walks through getting gcc and make installed for people unfamiliar with Cygwin.  Finding the others is pretty straightforward, the Search bar in the package selector works well.

Installing libevent

Gearmand requires an event notification library called libevent that you cannot get as a Cygwin package, which means it has to be installed from source.  You can get the source here.

  1. Download and unpack the latest libevent stable release.  At the time of this writing, I used libevent-1.4.14b-stable.
    NOTE: Download and unpack to a directory that does not contain spaces in the name, such as "C:/cygwin/home/Zombat/libevent-1.4.14b-stable".  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)!
  2. Open a Cygwin shell and cd to the unpacked libevent directory.
  3. Run the following commands:

./configure
make
make install

libevent should now be installed and ready to be used when compiling the Gearman job server.

Installing the Gearman job server, gearmand.exe

  1. Download and unpack the C implementation of gearmand from http://gearman.org/index.php?id=download
  2. Open a cygwin shell and cd to your unpacked gearmand directory.  Same rules apply as before, make sure you've unpacked in a directory with no spaces in the path!  libtool hates that, and your build may fail.
  3. Run the following commands:

./configure
make
make install

The Gearman job server should now be installed and ready to use!  Mine was installed at /usr/local/sbin/gearmand.exe, and running it with a "triple verbose" flag (-vvv) should produce the following:

gearmand.exe startup debug output

That's it for the job server.  When you want to start it, simply open a Cygwin shell and run gearmand.exe.  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.

Installing the Gearman Client and Worker API (Net_Gearman)

I chose to install the PEAR Client and Worker API, as it is native PHP and doesn't involve compiling PECL extensions.  The PEAR package is called Net_Gearman, and was originally written by Joe Stump at Digg.com.  It is old and out of date now, although there appears to be a more recent fork at http://github.com/brianlmoon/net_gearman.  I stuck with the older version, as I suspect it will meet my needs, and was readily available as a PEAR package.

This also makes installation relatively painless.  Assuming you've previously set PEAR up, then all you have to do is open a command window (not a Cygwin shell) and run:

pear install Net_Gearman-alpha

The "-alpha" portion is necessary, as Net_Gearman apparently never made it to a stable release version.  That being said, it has functioned well for me so far.  Perhaps someone will pick the project up in the future.

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.

转自:
http://www.phpvs.net/2010/11/30/installing-gearman-and-gearmand-on-windows-with-cygwin/


]]>aio,epoll,libevent,boost::asio解决的问?/title><link>http://www.shnenglu.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.shnenglu.com/guojingjia2006/archive/2012/11/09/194979.html</guid><wfw:comment>http://www.shnenglu.com/guojingjia2006/comments/194979.html</wfw:comment><comments>http://www.shnenglu.com/guojingjia2006/archive/2012/11/09/194979.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/guojingjia2006/comments/commentRss/194979.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/guojingjia2006/services/trackbacks/194979.html</trackback:ping><description><![CDATA[<div> aio是linux2.6以后内核实现的异步IOQ或者说他才是真正意义上的异步IO?br /> epoll作ؓselect的linux的替代品Q解决了selectfd_set的限制。性能优于select。而在maxq_上替代方案是kqueue?br /> libevent是一个跨q_异步解决ҎQ他Ҏ不同的^台提供了不同的异步方案,采用Reactor模型实现?br /> Boost::asio是一个跨q_的网l及底层IO的C++<a target="_blank">~程</a>库,实现了对TCP、UDP、ICMP、串口的支持。对于读写方式,ASIO支持同步和异步两U方式。采用了epoll来实玎ͼ插入了大量的信号处理。Asio库不需要单独便于,但是试q程中对boost::system的依赖可能会需要编译部分boost中的库?br /> muduo采用Reactor模型实现的网l库Q只支持<a target="_blank">Linux</a> 2.6.x下的q发非阻塞TCP|络~程Q不跨^収ͼ不支持udp和ipv6。吞吐量斚wmuduo比libevent2?8%Q在事g处理效率?面,muduo与libevent2M比较接近Qmuduo吞吐量比boost.asio?5%以上。性能斚w作ؓ解决大数据吞吐量很有优势Q但是对 q_和网l协议支持方面是一个问题?br /> ACE也是很经典的|络库,《C++|络~程》作者之手,设计_֦E度堪称一,支持协议范围也很q,但是使用复杂度和学习复杂度较高,一直有“学我者生Q用我者死”的评仗?br /> 需要注意的是他们的定位不同Qaio和epoll主要是对异步提供解决Ҏ不是|络库不提供|络支持Q而libevent也是主要解决IO的问题只提供单的http支持Qasio和muduoq有ACE一h高性能|络库?/div><img src ="http://www.shnenglu.com/guojingjia2006/aggbug/194979.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/guojingjia2006/" target="_blank">果?/a> 2012-11-09 15:56 <a href="http://www.shnenglu.com/guojingjia2006/archive/2012/11/09/194979.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>免费的C++囑Ş和游戏库http://www.shnenglu.com/guojingjia2006/archive/2012/06/15/178934.html果?/dc:creator>果?/author>Fri, 15 Jun 2012 06:29:00 GMThttp://www.shnenglu.com/guojingjia2006/archive/2012/06/15/178934.htmlhttp://www.shnenglu.com/guojingjia2006/comments/178934.htmlhttp://www.shnenglu.com/guojingjia2006/archive/2012/06/15/178934.html#Feedback0http://www.shnenglu.com/guojingjia2006/comments/commentRss/178934.htmlhttp://www.shnenglu.com/guojingjia2006/services/trackbacks/178934.htmlShare

C++ is a multi paradigm, free form complied, general purpose and thus a very powerful language used basically forthe purpose of programming. This language is regarded as an intermediatelevel language .The main reason for this is that it consists of both high level as well aslow level features.

It is one of the most popularprogramming languages due to many reasons. It has application domains which include system software, device drivers, application software and many other including client applications and entertainment software of which the best example is a video game.

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.

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 applications. Visit this list and share your thought in our comment section below.

1) Antigrain

Anti-Grain Geometry (AGG) is an Open Source, free of charge graphic library, written in industrially standard C++. The terms and conditions of use AGG are described on The License page. AGG doesn’t depend on any graphic API or technology. Basically, you can think of AGG as of a rendering engine that produces pixel images in memory from some vectorial data.

2) Amanith

AmanithVG SRE 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.

3) Codehead

4) Oscilloscope Lib

5) Lib SDL

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 “Civilization: Call To Power.”

6) Ogre 3d

OGRE (Object-Oriented Graphics Rendering Engine) 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.

转自:

http://zoomzum.com/6-free-c-graphics-and-game-libraries/



]]>
c/c++通用内存泄漏框架GMFD(General Memory Fault Detection Framework)http://www.shnenglu.com/guojingjia2006/archive/2012/01/16/164246.html果?/dc:creator>果?/author>Mon, 16 Jan 2012 05:03:00 GMThttp://www.shnenglu.com/guojingjia2006/archive/2012/01/16/164246.htmlhttp://www.shnenglu.com/guojingjia2006/comments/164246.htmlhttp://www.shnenglu.com/guojingjia2006/archive/2012/01/16/164246.html#Feedback0http://www.shnenglu.com/guojingjia2006/comments/commentRss/164246.htmlhttp://www.shnenglu.com/guojingjia2006/services/trackbacks/164246.html1 背景Q?/span>
       x86q_有完善的用户态检内存工h如valgrind{,可以监控E序q行中详l的内存信息Q从而精定位内存问题。然而随着新^台的快速诞生(比如Tilera的TilePro64 CPU)Q这些工具不能被及时地移植,D新^台缺乏相应的手段来定位内存错误,如内存越界,泄漏{,而只能用粗_度的方法topQfree {指令观察进E的动态内存总额。其~点是粒度太_,而且内存的L变化有很多原因引P在复杂的pȝ里,很难_定位内存问题的根源,甚至会漏报错报,q严重媄响了新^収ͼ如Tilera)开发与试的效率。针对这个问题,我们提出了一个通用的新q_针对c/c++内存错误框架?br />       该框架可适用于Q何^台。其通过重写标准库的内存分配和释攑և敎ͼ如malloc, new, new[], free,delete,delete[]{), 以及l护一个全局的内存分配map数据l构实现。重写后的内存分配比如my_malloc首先调用pȝmalloc功能Q然后记录每一ơmalloc执行q程中的内存操作信息Q包括文件名、行号以及内存尺寸,函数调用栈)Q以指针gؓ key|存进l护的全局map表。而重写的my_free则是Ҏ传入的指针值在 map 中查扄应的数据ƈ之删除Q而后调用pȝ的free 指针所指向的内存块释放。这样当E序退出的时候,map 中的剩余的数据项是我们期望的内存泄漏信息。我们可以输出泄漏内存块的详l日志,比如文g名,行号{等。这大大提高类似Tileraq_的内存问题追查效率,提高开发和试的速度和质量?/em>
2 基本原理Q?/span>
1)    通过重写非共享内存分配释攑և数malloc, new, new[]Qfree,delete,delete[]截获 它们在执行过E中的内存操作信息。重载Ş式如下:
※   void* malloc( size_t nSize, char* pszFileName, int nLineNum )
※   void* new( size_t nSize, char* pszFileName, int nLineNum )
※   void* operator new[]( size_t nSize, char* pszFileName, int nLineNum )
※   void free( void *ptr )
※   void delete( void *ptr )
※   void operator delete[]( void *ptr )

2)    通过重写׃n内存分配释放函数mspace_mallocQmspace_freeQ重写Ş式如下:

※   void* my_mspace_malloc( mspace msp,unsigned int Size, char* pszFileName, int nLineNum )
※   void my_mspace_free(mspace msp, void *ptr )

3)    我们对malloc, new, new[]Qmspace_mallocq行了重载,参数包括size_t nSize、文件名和行Pq里的文件名和行号就是这ơmalloc, new, new[]Qmspace_malloc操作W被调用时所在的文g名和行号Q这个信息将在发现内存泄漏时输出Q以帮助定位泄漏具体位置。对?free,delete,delete[]Qmspace_free参数为指针地址?br />3 实例Q?/span>
以My_malloc, My_freeZQ重写函数结构如下:
 
1.    在重写的my_malloc函数版本中,我们调用malloc 的原始版本ƈ相应的 size_t 参数传入Q然后,我们malloc的原始版本返回的指针g及该ơ分配所在的文g名和行号信息记录下来Q这里采用STL ?map数据l构存储Q以指针gؓ key |文g名,行号{信息作Z个结构体是value倹{?br />My_free重写函数l构如下Q?br />
 
2.    当my_free 被调用时Q我们根据传入的指针值在 map 中找到相应的数据ƈ之删除Q而后调用 free 指针所指向的内存块释放。这样当E序退出的时候,map 中的剩余的数据项是我们企图的内存泄漏信息?br />4 实现关键点:
1)    如何取得内存分配代码所在的文g名和行号Q?/strong>
利用 C 的预~译?__FILE__ ?__LINE__Q这两个宏将在编译时在指定位|展开文g的文件名和该行的行号
2)    利用宏定义开兛_定走普通分支还是内存检分支?
#if defined( MEM_DEBUG )
#define malloc DEBUG_MALLOC
#define free DEBUG_FREE
#endif
3)    何时创徏用于存储内存数据?map 数据l构Q如何管理,何时打印内存泄漏信息Q?/strong>
设计一个类来封装这?map 以及对它的插入删除操作,然后构造这个类的一个全局对象QappMemoryQ,在全局对象QappMemoryQ的构造函C创徏q初始化q个数据l?构,而在其析构函CҎ据结构中剩余数据q行分析和输出。new 中将调用q个全局对象?insert 接口指针、文件名、行受内存块大小{信息以指针gؓ key 记录?map 中,在delete 中调?erase 接口对应指针值的 map 中的数据删除,同时?map 的访问需要进行互斥同步,因ؓ同一旉可能会有多个q程q行堆上的内存操作?br />4)    如何为非׃n内存甌mapQ如何ؓ׃n内存甌mapQ?/strong>
非共享内存的map,对于多进E则有多个mapQ可按(3Q的Ҏ处理。而对于共享内存,可能Aq程甌到Bq程才释放,但是每个q程一个map,我们L描这些每个map时就会出现误报的现象Q因此需要采取将map攑օ׃n内存ҎQ我们申请一块共享内存区域ؓmap,q个map对各q程是共享的。当E序中各q程调用׃n内存Ӟ各q程分配的指针及文g名行L详细信息存进q共享的map。程序结束时Q扫描该׃n的map,p得到未释攄信息。将 map攑օ׃n内存使用c++标准库时需要我们自己实C个基于共享内存的allocatorQ替换map默认的allocatorQ在q个allocator中实现map的内存分配方案。也可以使用boost库(1.35以上版本Q,它增加了一个叫做boost::interprocess的库Q具体可参考http://blog.cong.co/stl-alloc.html
5)    如何使用该工P
内存泄露框架提供接口libmemck.hQ内容如?/p>


 在被试E序里包含如下代码即可?br /> 
6)    何时如何捕获信号Q生成leak文gQ?/strong>
定义一个全局的类得对象,在该cd构造函数里通过signal函数捕获SIGINT、SIGABRT、SIGFPE、SIGTERM信号Q当捕获到这些信号其中之一Ӟ开始扫描mapq将map剩余信息写入leak文g展示?br />7)    对界资源的控制Q?/strong>
׃n内存的各q程׃n的mapQ各q程间进行读写操作需要加锁,我们q里采用的是信号灯实现?br />非共享内存各个进E对应的mapQ在各进E进行插入删除操作时也需要加锁实?br />8)    E序中malloc作ؓ函数指针Q?/strong>
׃原型malloc(size)重写为my_malloc(sizeQ__FILE__,__LINE__),q样׃函数cd不一_DE序调用该工h~译无法通过Q真对这U情늚解决办法为:重写malloc(size)为my_malloc_p(size)q样除了文g名和行号无法得知外,泄露的多内存可以报出?br />
转自http://hi.baidu.com/baiduqa/blog/item/e4c991c5ef46e5c7d10060fb.html



]]>
<?gt;boost::any的用法、优点和~点以及源代码分?http://www.shnenglu.com/guojingjia2006/archive/2011/06/16/148802.html果?/dc:creator>果?/author>Thu, 16 Jun 2011 10:32:00 GMThttp://www.shnenglu.com/guojingjia2006/archive/2011/06/16/148802.htmlhttp://www.shnenglu.com/guojingjia2006/comments/148802.htmlhttp://www.shnenglu.com/guojingjia2006/archive/2011/06/16/148802.html#Feedback0http://www.shnenglu.com/guojingjia2006/comments/commentRss/148802.htmlhttp://www.shnenglu.com/guojingjia2006/services/trackbacks/148802.html
01.#include <iostream>  
02.#include <list>  
03.#include <boost/any.hpp>  
04. 
05.typedef std::list<boost::any> list_any;  
06. 
07.//关键部分Q可以存放Q意类型的对象  
08.void fill_list(list_any& la)  
09.{      
10.    la.push_back(10);//存放常数   
11.    la.push_back( std::string("dyunze") );//存放字符串对象;注意la.push_back(“dyunze”)错误Q因Z被当错字W串数组  
12.}  
13. 
14.//Ҏcdq行昄  
15.void show_list(list_any& la)  
16.{  
17.    list_any::iterator it;  
18.    boost::any anyone;  
19. 
20.    for( it = la.begin(); it != la.end(); it++ )  
21.    {     
22.        anyone = *it;  
23. 
24.        if( anyone.type() == typeid(int) )  
25.            std::cout<<boost::any_cast<int>(*it)<<std::endl;  
26.        else if( anyone.type() == typeid(std::string) )  
27.            std::cout<<boost::any_cast<std::string>(*it).c_str()<<std::endl;  
28.    }  
29.}  
30. 
31.int main()  
32.{  
33.    list_any la;  
34.    fill_list(la);  
35.    show_list(la);  
36. 
37.    return 0;  
38.} 
#include <iostream>
#include <list>
#include <boost/any.hpp>

typedef std::list<boost::any> list_any;

//关键部分Q可以存放Q意类型的对象
void fill_list(list_any& la)
{   
    la.push_back(10);//存放常数
    la.push_back( std::string("dyunze") );//存放字符串对象;注意la.push_back(“dyunze”)错误Q因Z被当错字W串数组
}

//Ҏcdq行昄
void show_list(list_any& la)
{
    list_any::iterator it;
    boost::any anyone;

    for( it = la.begin(); it != la.end(); it++ )
    {   
        anyone = *it;

        if( anyone.type() == typeid(int) )
            std::cout<<boost::any_cast<int>(*it)<<std::endl;
        else if( anyone.type() == typeid(std::string) )
            std::cout<<boost::any_cast<std::string>(*it).c_str()<<std::endl;
    }
}

int main()
{
    list_any la;
    fill_list(la);
    show_list(la);

    return 0;
}

boost::any的优点:

     对设计模式理解的朋友都会知道合成模式。因为多态只有在使用指针或引用的情况下才能显玎ͼ所以std容器中只能存放指针或引用Q但实际上只能存放指针,无法存放引用Q这个好像是c++的不_Q。如Q?br />
     std::list<BaseClass*> mylist;

q样Q我们就要对指针所指向内容的生存周期操?可能需要程序员适时删除甌的内存;但是׃存放指针Q插?删除的效率高)Q而用boost::any可能避免这U情况,因ؓ我们可以存放cd本nQ当然存放指针也可以Q。这是boost::any的优点之一?br />
    boost::any另一个优Ҏ可以存放Mcd。而前面提到的mylist只能存放BaseClasscL针以及其l承cȝ指针?br />
boost::any的缺点:

    ׃boost::any可以存放McdQ自然它用不了多态特性,没有l一的接口,所以在获取容器中的元素旉要实现判别元素的真正cdQ这增加了程序员的负担。与面向对象~程思想有些矛盾Q但整个标准c++模板库何不是如此,用那些牛人的话来_?#8220;有益补充”?br />
   MQ有利必有弊Q没有十全十的?br />
  

分析q模仿boost::anyQ?br />
     M一下boost::any的源代码Qƈ模仿一下其实现(相当一部分时拷贝原代码)Q下面是代码(只包含必要功??br />
实现any的功能主要由三部分组成:
1Qanyc?br />2Q真正保存数据的holdercd其基cplaceholder
3Q获取真正数据的模板函数any_castQ类型{换的功能?br />
view plaincopy to clipboardprint?
01.#include <iostream>  
02.#include <list>  
03.#include <cassert>  
04. 
05.//自定义的anyc?nbsp; 
06.class any  
07.{  
08.public:  
09.      
10.    //保存真正数据的接口类  
11.    class placeholder  
12.    {  
13.    public:       
14.        virtual ~placeholder()  
15.        {  
16.        }  
17.    public:   
18. 
19.        virtual const std::type_info & type() const = 0;  
20.        virtual placeholder * clone() const = 0;      
21.    };  
22. 
23.    //真正保存和获取数据的cR?nbsp; 
24.    template<typename ValueType>  
25.    class holder : public placeholder  
26.    {  
27.    public:           
28.        holder(const ValueType & value): held(value)  
29.        {  
30.        }  
31. 
32.    public:   
33. 
34.        virtual const std::type_info & type() const 
35.        {  
36.            return typeid(ValueType);  
37.        }  
38. 
39.        virtual placeholder * clone() const 
40.        {  
41.            return new holder(held);//使用了原型模?nbsp; 
42.        }  
43. 
44.    public:   
45. 
46.        //真正的数据,׃存在q里  
47.        ValueType held;  
48.    };  
49. 
50.public:  
51. 
52.    any(): content(NULL)     
53.    {         
54.    }  
55. 
56.    //模板构造函敎ͼ参数可以是Q意类型,真正的数据保存在content?nbsp; 
57.    template<typename ValueType>  
58.    any(const ValueType & value): content(new holder<ValueType>(value))  
59.    {  
60.    }    
61. 
62.    //拯构造函?nbsp; 
63.    any(const any & other)  
64.        : content(other.content ? other.content->clone() : 0)  
65.    {  
66.    }  
67. 
68.    //析构函数Q删除保存数据的content对象  
69.    ~any()  
70.    {  
71.        if(NULL != content)  
72.            delete content;  
73.    }  
74. 
75.private:  
76.    //一个placeholde对象指针Q指向其子类folder的一个实?nbsp; 
77.    // 即content( new holder<ValueType>(value) )语句  
78.    placeholder* content;  
79. 
80.    template<typename ValueType> friend ValueType any_cast(const any& operand);  
81.public:   
82. 
83.    //查询真实数据的类型?nbsp; 
84.    const std::type_info & type() const 
85.    {  
86.        return content ? content->type() : typeid(void);  
87.    }  
88.};  
89. 
90. 
91.//获取content->helder数据的方法。用来获取真正的数据  
92.template<typename ValueType>  
93.ValueType any_cast(const any& operand)  
94.{  
95.    assert( operand.type() == typeid(ValueType) );  
96.    return static_cast<any::holder<ValueType> *>(operand.content)->held;  
97.}  
98. 
99.//下代码是使用CZ  
100. 
101.typedef std::list<any> list_any;  
102. 
103.void fill_list(list_any& la)  
104.{      
105.    la.push_back(10);//存放常数Q调用了any的模板构造函敎ͼ下同  
106.    la.push_back( std::string("我是string") );//存放字符串对象;注意la.push_back(“dyunze”)错误Q因Z被当错字W串数组  
107. 
108.    char* p = "我是帔R区字W串abc";  
109.    la.push_back(p);//可以存放指针Q但要注意指针的失效问题  
110.}  
111. 
112.//Ҏcdq行昄  
113.void show_list(list_any& la)  
114.{  
115.    list_any::iterator it;  
116. 
117.    for( it = la.begin(); it != la.end(); it++ )  
118.    {     
119. 
120.        if( (*it).type() == typeid(int) )  
121.            std::cout<<any_cast<int>(*it)<<std::endl;  
122.        else if( (*it).type() == typeid(std::string) )  
123.            std::cout<<any_cast<std::string>(*it).c_str()<<std::endl;  
124.        else if( (*it).type() == typeid(char*) )  
125.            std::cout<<any_cast<char*>(*it)<<std::endl;  
126.    }  
127.}  
128. 
129.int main()  
130.{  
131.    list_any la;  
132.    fill_list(la);  
133.    show_list(la);  
134. 
135.    return 0;  
136.} 

 boost::any是一个很有趣的类Q刚刚开始我q以为其是一个variantcdQ?br />能够Q意类型g存进去,能够以Q意类型D出来Q不q我错了 :(
  boost::any的作者认为,所谓generic type有三个层面的解释ҎQ?br />  1.cMvariantcd那样Lq行cd转换Q可以保存一?int)5q去Q?br />    M?string)"5"出来。Win下面的VARIANTcd是以一个巨大的
    union实现的类似功能,使用灉|但效率较?br />  2.区别对待包含值的cdQ保存一?int)5q去Q不会被隐式转换?br />    (string)'5'或?double)5.0Q这h率较高且cd安全Q?br />    不必担心ambiguous conversions
  3.对包含值类型不加区别,例如把所有保存的值强制{换ؓvoid *保存
    d时再有程序员判断其类型。这h率虽最高但无法保证cd安全
  boost::any选择了第二层面的设计思\Q它允许用户Q意类型g?br />q一个anycd变量Q但内部q不改变值的cdQƈ提供Ҏ让用户在使用?br />d/被动q行cd判断?br />
  在实现方面,boost::any使用两层内部cplaceholder和holder保存
实际cd的倹{类placeholder只是一个接口,模板cholder是特定类?br />的实现。其中type()Ҏ获取实际值类型,即typeid(ValueType);
clone()Ҏ获取值的拯return new holder(held);
  virtual const std::type_info & type() const
  virtual placeholder * clone() const
  其值的cd信息不象Win的VARIANT那样以专门的字段保存Q?br />而是通过模板参数形式静态保存。这h率更高(仅在~译期)Q?br />
通用性更强(Mcd都可以,真正anyQ但灉|性不如VARIANT
  在进行拷贝构?赋?swapӞ都直接将整个placeholder换掉Q?br />q样可以保证值类型的延箋性?br />
  在用方面,提供了主?被动q行cd的Ҏ?br />  可以使用any::type()Ҏd值类?br />bool is_int(const boost::any & operand)
{
    return operand.type() == typeid(int);
}
  也可以通过any_cast函数被动q行。此函数与C++中的*_cast
pd关键字有相同的语法规范,试q行cd转换Q如cd不匹配则?br />指针转换q回NULLQ对引用转换抛出boost::bad_any_cast异常
  boost::any str = string("12345");
  try
  {
    cout << boost::any_cast<int>(str) << endl;
  }
  catch(boost::bad_any_cast e)
  {
    cerr << e.what() << endl;
  }


  在应用方面,anycd适合于类型不同但使用相关的倹{如C++?..
形式的函数参数本事不是类型安全的Q可以通过vector<any>攚w之
然后在用时类型是否匹配,如可攚wprintf?br />  void safe_printf(const char *format, const vector<any>& params)
  {
    int index = 0;
    for(const char *pch = format; *pch; pch++)
    {
      switch(*pch)
      {
        case '%':
        {
          switch(*++pch)
          {
            case 'i':
            case 'd':
            {
              if(params[index].type() == typeid(int) ||
                 params[index].type() == typeid(short))
              {
                ...
              }
              else
                throw ...
            }
          }
        }
        case '\':
        {
          ...
        }
        default:
        {
          putchar(*pch);
        }
      }
    }
  }

附:boost::any.hpp
#ifndef BOOST_ANY_INCLUDED
#define BOOST_ANY_INCLUDED

// what:  variant type boost::any
// who:   contributed by Kevlin Henney,
//        with features contributed and bugs found by
//        Ed Brey, Mark Rodgers, Peter Dimov, and James Curran
// when:  July 2001
// where: tested with BCC 5.5, MSVC 6.0, and g++ 2.95

#include <algorithm>
#include <typeinfo>

#include "boost/config.hpp"

namespace boost
{
    class any
    {
    public: // structors

        any()
          : content(0)
        {
        }

        template<typename ValueType>
        any(const ValueType & value)
          : content(new holder<ValueType>(value))
        {
        }

        any(const any & other)
          : content(other.content ? other.content->clone() : 0)
        {
        }

        ~any()
        {
            delete content;
        }

    public: // modifiers

        any & swap(any & rhs)
        {
            std::swap(content, rhs.content);
            return *this;
        }

        template<typename ValueType>
        any & operator=(const ValueType & rhs)
        {
            any(rhs).swap(*this);
            return *this;
        }

        any & operator=(const any & rhs)
        {
            any(rhs).swap(*this);
            return *this;
        }

    public: // queries

        bool empty() const
        {
            return !content;
        }

        const std::type_info & type() const
        {
            return content ? content->type() : typeid(void);
        }

#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
    private: // types
#else
    public: // types (public so any_cast can be non-friend)
#endif


        class placeholder
        {
        public: // structors
    
            virtual ~placeholder()
            {
            }

        public: // queries

            virtual const std::type_info & type() const = 0;

            virtual placeholder * clone() const = 0;
    
        };

        template<typename ValueType>
        class holder : public placeholder
        {
        public: // structors

            holder(const ValueType & value)
              : held(value)
            {
            }

        public: // queries

            virtual const std::type_info & type() const
            {
                return typeid(ValueType);
            }

            virtual placeholder * clone() const
            {

                return new holder(held);
            }

        public: // representation

            ValueType held;

        };

#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS

    private: // representation

        template<typename ValueType>
        friend ValueType * any_cast(any *);

#else

    public: // representation (public so any_cast can be non-friend)

#endif

        placeholder * content;

    };

    class bad_any_cast : public std::bad_cast
    {
    public:
        virtual const char * what() const throw()
        {
            return "boost::bad_any_cast: "
                   "failed conversion using boost::any_cast";
        }
    };

    template<typename ValueType>
    ValueType * any_cast(any * operand)
    {
        return operand && operand->type() == typeid(ValueType)
                    ? &static_cast<any::holder<ValueType> *>(operand->content)->held
                    : 0;
    }

    template<typename ValueType>
    const ValueType * any_cast(const any * operand)
    {
        return any_cast<ValueType>(const_cast<any *>(operand));
    }

    template<typename ValueType>
    ValueType any_cast(const any & operand)
    {
        const ValueType * result = any_cast<ValueType>(&operand);
        if(!result)
            throw bad_any_cast();
        return *result;
    }

}

// Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved.
//
// Permission to use, copy, modify, and distribute this software for any
// purpose is hereby granted without fee, provided that this copyright and
// permissions notice appear in all copies and derivatives.
//
// This software is provided "as is" without express or implied warranty.

#endif



]]>c++ 内存?/title><link>http://www.shnenglu.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.shnenglu.com/guojingjia2006/archive/2011/04/05/143473.html</guid><wfw:comment>http://www.shnenglu.com/guojingjia2006/comments/143473.html</wfw:comment><comments>http://www.shnenglu.com/guojingjia2006/archive/2011/04/05/143473.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/guojingjia2006/comments/commentRss/143473.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/guojingjia2006/services/trackbacks/143473.html</trackback:ping><description><![CDATA[<p><a name=N100A5><span id="rd7tbrb" class=atitle>引言</span></a></p> <p>本书主要针对的是 C++ E序的性能优化Q深入介l?C++ E序性能优化的方法和实例。全书由 4 个篇l成Q第 1 介l?C++ 语言的对象模型,该篇是优?C++ E序的基Q第 2 主要针对如何优?C++ E序的内存用;W?3 介l如何优化程序的启动性能Q第 4 介l了三类性能优化工具Q即内存分析工具、性能分析工具?I/O 工P它们是测量程序性能的利器?/p> <p>本章首先单介l自定义内存池性能优化的原理,然后列D软g开发中常用的内存池的不同类型,q给出具体实现的实例?/p> <div id="tflhzbj" class=ibm-alternate-rule></div> <p class="ibm-ind-link ibm-back-to-top"><a class=ibm-anchor-up-link ><u><font color=#0066cc>回页?/font></u></a></p> <p><a name=N100B1><span id="17bbxfd" class=atitle>6.1 自定义内存池性能优化的原?/span></a></p> <div id="p7lrvvl" class="ibm-container dw-container-sidebar ibm-alternate-two"> <div id="779pnz9" class=ibm-container-body> <p> </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>书名Q?/strong>《C++应用E序性能优化?<br><strong>作者:</strong>冯宏华、徐莏V程q、汪?{编?<br><strong>出版C:</strong>电子工业出版C?<br><strong>出版日期Q?/strong>2007 q?03 ?<br><strong>ISBNQ?/strong>978-7-121-03831-0 <br><strong>购买Q?/strong> <a ><u><font color=#0066cc>中国互动出版|?/font></u></a>?a ><u><font color=#0066cc>dearbook</font></u></a> </td> </tr> <tr> <td colSpan=3> <p><strong>推荐章节:</strong> </p> <ul> <li><a ><u><font color=#0066cc>前言</font></u></a> ?<a ><u><font color=#0066cc>目录</font></u></a> </li> <li><a ><u><font color=#0066cc>W?2 章:C++ 语言Ҏ的性能分析</font></u></a> </li> <li><a ><u><font color=#0066cc>W?6 章:内存?/font></u></a> </li> </ul> <p> </p> <p>更多推荐书籍Q请讉K <a ><u><font color=#0066cc>developerWorks 图书频道</font></u></a>?/p> <p>Ƣ迎您对本书提出宝贵的反馈意见。您可以通过本页面最下方?<a ><u><font color=#0066cc></font></u></a> 栏目为本文打分,q反馈您的徏议和意见?/p> <p>如果您对 developerWorks 图书频道有什么好的徏议,<a ><u><font color=#0066cc>Ƣ迎您将发给我们</font></u></a>?/p> </td> </tr> </tbody> </table> <p> </p> </div> </div> <p>如前所qͼ读者已l了解到"???的区别。而在~程实践中,不可避免地要大量用到堆上的内存。例如在E序中维护一个链表的数据l构Ӟ每次新增或者删除一个链表的节点Q都需要从内存堆上分配或者释放一定的内存Q在l护一个动态数l时Q如果动态数l的大小不能满E序需要时Q也要在内存堆上分配新的内存I间?/p> <p><a name=N10145><span id="j7vpd79" class=smalltitle>6.1.1 默认内存理函数的不?/span></a></p> <p>利用默认的内存管理函数new/delete或malloc/free在堆上分配和释放内存会有一些额外的开销?/p> <p>pȝ在接收到分配一定大内存的hӞ首先查找内部l护的内存空闲块表,q且需要根据一定的法Q例如分配最先找到的不小于申请大的内存块给h者,或者分配最适于甌大小的内存块Q或者分配最大空闲的内存块等Q找到合适大的I闲内存块。如果该I闲内存块过大,q需要切割成已分配的部分和较的I闲块。然后系l更新内存空闲块表,完成一ơ内存分配。类似地Q在释放内存Ӟpȝ把释攄内存块重新加入到I闲内存块表中。如果有可能的话Q可以把盔R的空闲块合ƈ成较大的I闲块?/p> <p>默认的内存管理函数还考虑到多U程的应用,需要在每次分配和释攑ֆ存时加锁Q同样增加了开销?/p> <p>可见Q如果应用程序频J地在堆上分配和释放内存Q则会导致性能的损失。ƈ且会使系l中出现大量的内存碎片,降低内存的利用率?/p> <p>默认的分配和释放内存法自然也考虑了性能Q然而这些内存管理算法的通用版本Z应付更复杂、更q泛的情况,需要做更多的额外工作。而对于某一个具体的应用E序来说Q适合自n特定的内存分配释放模式的自定义内存池则可以获得更好的性能?/p> <p><a name=N1015A><span id="7rvhd9z" class=smalltitle>6.1.2 内存池的定义和分c?/span></a></p> <p>自定义内存池的思想通过q个"?字表露无疑,应用E序可以通过pȝ的内存分配调用预先一ơ性申请适当大小的内存作Z个内存池Q之后应用程序自己对内存的分配和释放则可以通过q个内存池来完成。只有当内存池大需要动态扩展时Q才需要再调用pȝ的内存分配函敎ͼ其他旉对内存的一切操作都在应用程序的掌控之中?/p> <p>应用E序自定义的内存池根据不同的适用场景又有不同的类型?/p> <p>从线E安全的角度来分Q内存池可以分ؓ单线E内存池和多U程内存池。单U程内存池整个生命周期只被一个线E用,因而不需要考虑互斥讉K的问题;多线E内存池有可能被多个U程׃nQ因此则需要在每次分配和释攑ֆ存时加锁。相对而言Q单U程内存池性能更高Q而多U程内存池适用范围更广?/p> <p>从内存池可分配内存单元大来分,可以分ؓ固定内存池和可变内存池。所谓固定内存池是指应用E序每次从内存池中分配出来的内存单元大小事先已经定Q是固定不变的;而可变内存池则每ơ分配的内存单元大小可以按需变化Q应用范围更q,而性能比固定内存池要低?/p> <p><a name=N1016C><span id="1lx7pz9" class=smalltitle>6.1.3 内存池工作原理示?/span></a></p> <p>下面以固定内存池Z说明内存池的工作原理Q如?-1所C?/p> <br><a name=N10177><strong>?-1 固定内存?/strong></a><br><img border=0 alt="?-1 固定内存? src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_1.gif" width=498 height=211> <br> <p>固定内存池由一pd固定大小的内存块l成Q每一个内存块又包含了固定数量和大的内存单元?/p> <p>如图6-1所C,该内存池一共包?个内存块。在内存池初ơ生成时Q只向系l申请了一个内存块Q返回的指针作ؓ整个内存池的头指针。之后随着应用E序对内存的不断需求,内存池判断需要动态扩大时Q才再次向系l申h的内存块Qƈ把所有这些内存块通过指针链接h。对于操作系l来_它已lؓ该应用程序分配了4个等大小的内存块。由于是大小固定的,所以分配的速度比较快;而对于应用程序来_其内存池开辟了一定大,内存池内部却q有剩余的空间?/p> <p>例如攑֤来看W?个内存块Q其中包含一部分内存池块头信息和3个大相{的内存池单元。单?和单?是空闲的Q单?已经分配。当应用E序需要通过该内存池分配一个单元大的内存Ӟ只需要简单遍历所有的内存池块头信息,快速定位到q有I闲单元的那个内存池块。然后根据该块的块头信息直接定位到第1个空闲的单元地址Q把q个地址q回Qƈ且标C一个空闲单元即可;当应用程序释放某一个内存池单元Ӟ直接在对应的内存池块头信息中标记该内存单元ؓI闲单元卛_?/p> <p>可见与系l管理内存相比,内存池的操作非常q速,它在性能优化斚w的优点主要如下?/p> <p>Q?Q针对特D情况,例如需要频J分配释攑֛定大的内存对象Ӟ不需要复杂的分配法和多U程保护。也不需要维护内存空闲表的额外开销Q从而获得较高的性能?/p> <p>Q?Q由于开辟一定数量的q箋内存I间作ؓ内存池块Q因而一定程度上提高了程序局部性,提升了程序性能?/p> <p>Q?Q比较容易控刉边界寚w和内存字节对齐,没有内存片的问题?/p> <div id="dz1vh79" class=ibm-alternate-rule></div> <p class="ibm-ind-link ibm-back-to-top"><a class=ibm-anchor-up-link ><u><font color=#0066cc>回页?/font></u></a></p> <p><a name=N1019C><span id="fjhxr7r" class=atitle>6.2 一个内存池的实现实?/span></a></p> <p>本节分析在某个大型应用程序实际应用到的一个内存池实现Qƈ详细讲解其用方法与工作原理。这是一个应用于单线E环境且分配单元大小固定的内存池Q一般用来ؓ执行时会动态频J地创徏且可能会被多ơ创建的cd象或者结构体分配内存?/p> <p>本节首先讲解该内存池的数据结构声明及囄Q接着描述其原理及行ؓ特征。然后逐一讲解实现l节Q最后介l如何在实际E序中应用此内存池,q与使用普通内存函数申请内存的E序性能作比较?/p> <p><a name=N101A8><span id="bvth7rb" 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为内存池中附着在真正用来ؓ内存h分配内存的内存块头部的结构体Q它描述了与之联pȝ内存块的使用信息Q?/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>此内存池的数据结构如?-2所C?/p> <br><a name=N101CB><strong>?-2 内存池的数据l构</strong></a><br><img border=0 alt="?-2 内存池的数据l构" 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 id="vzj799v" class=smalltitle>6.2.2 M机制</span></a></p> <p>此内存池的M机制如下?/p> <p>Q?Q在q行q程中,MemoryPool内存池可能会有多个用来满_存申误求的内存块,q些内存块是从进E堆中开辟的一个较大的q箋内存区域Q它׃个MemoryBlockl构体和多个可供分配的内存单元组成,所有内存块l成了一个内存块链表QMemoryPool 的pBlock是这个链表的头。对每个内存块,都可以通过其头部的MemoryBlockl构体的pNext成员讉K紧跟在其后面的那个内存块?/p> <p>Q?Q每个内存块׃部分l成Q即一个MemoryBlockl构体和多个内存分配单元。这些内存分配单元大固定(?MemoryPool的nUnitSize表示Q,MemoryBlockl构体ƈ不维护那些已l分配的单元的信息;相反Q它只维护没有分配的自由分配单元的信息。它有两个成员比较重要:nFree和nFirst。nFree记录q个内存块中q有多少个自由分配单元,而nFirst则记录下一个可供分配的单元的编受每一个自由分配单元的头两个字节(即一个USHORT型|记录了紧跟它之后的下一个自由分配单元的~号Q这P通过利用每个自由分配单元的头两个字节Q一个MemoryBlock中的所有自由分配单元被链接h?/p> <p>Q?Q当有新的内存请求到来时QMemoryPool会通过pBlock遍历MemoryBlock链表Q直到找到某?MemoryBlock所在的内存块,其中q有自由分配单元Q通过MemoryBlockl构体的nFree成员是否大于0Q。如果找到这L内存块,取得其MemoryBlock的nFirst|此ؓ该内存块中第1个可供分配的自由单元的编P。然后根据这个编号定位到该自由分配单元的起始位置Q因为所有分配单元大固定,因此每个分配单元的v始位|都可以通过~号分配单元大小来偏Ud位)Q这个位|就是用来满xơ内存申误求的内存的v始地址。但在返回这个地址前,需要首先将该位|开始的头两个字节的|q两个字节D录其之后的下一个自由分配单元的~号Q赋l本内存块的 MemoryBlock的nFirst成员。这样下一ơ的h׃用这个编号对应的内存单元来满I同时此内存块的MemoryBlock的nFree 递减1Q然后才刚才定位到的内存单元的起始位置作ؓ此次内存h的返回地址q回l调用者?/p> <p>Q?Q如果从现有的内存块中找不到一个自q内存分配单元Q当W?ơ请求内存,以及现有的所有内存块中的所有内存分配单元都已经被分配时会发生这U情形)QMemoryPool׃从进E堆中申请一个内存块Q这个内存块包括一个MemoryBlockl构体,及紧d后的多个内存分配单元Q假讑ֆ存分配单元的个数为nQn可以取值MemoryPool中的nInitSize或者nGrowSizeQ,甌完后Qƈ不会立刻其中的一个分配单元分配出去,而是需要首先初始化q个内存块。初始化的操作包括设|MemoryBlock的nSize为所有内存分配单元的大小Q注意,q不包括MemoryBlockl构体的大小Q、nFree为n-1Q注意,q里是n-1而不是nQ因为此ơ新内存块就是ؓ了满一ơ新的内存请求而申LQ马上就会分配一块自由存储单元出去,如果设ؓn-1Q分配一个自由存储单元后无须再将n递减1Q,nFirst?Q已l知道nFirstZ一个可以分配的自由存储单元的编受ؓ1的原因与nFree为n-1相同Q即立即会将~号?的自由分配单元分配出厅R现在设?Q其后不用修改nFirst的|QMemoryBlock的构造需要做更重要的事情Q即编号ؓ0的分配单元之后的所有自由分配单元链接v来。如前所qͼ每个自由分配单元的头两个字节用来存储下一个自由分配单元的~号。另外,因ؓ每个分配单元大小固定Q所以可以通过其编号和单元大小QMemoryPool的nUnitSize成员Q的乘积作ؓ偏移D行定位。现在唯一的问题是定位从哪个地址开始?{案是MemoryBlock的aData[1]成员开始。因为aData[1]实际上是属于MemoryBlockl构体的QMemoryBlockl构体的最后一个字节)Q所以实质上QMemoryBlockl构体的最后一个字节也用做被分配出ȝ分配单元的一部分。因为整个内存块由MemoryBlockl构体和整数个分配单元组成,q意味着内存块的最后一个字节会被浪费,q个字节在图6-2中用位于两个内存的最后部分的黑背景的小块标识。确定了分配单元的v始位|后Q将自由分配单元链接h的工作就很容易了。即从aData位置开始,每隔nUnitSize大小取其头两个字节,记录其之后的自由分配单元的编受因为刚开始所有分配单元都是自qQ所以这个编号就是自w编号加1Q即位置上紧跟其后的单元的编受初始化后,此内存块的W?个分配单元的起始地址q回Q已l知道这个地址是aData?/p> <p>Q?Q当某个被分配的单元因ؓdelete需要回收时Q该单元q不会返回给q程堆,而是q回lMemoryPool。返回时QMemoryPool能够知道该单元的起始地址。这ӞMemoryPool开始遍历其所l护的内存块链表Q判断该单元的v始地址是否落在某个内存块的地址范围内。如果不在所有内存地址范围内,则这个被回收的单元不属于q个MemoryPoolQ如果在某个内存块的地址范围内,那么它会这个刚刚回收的分配单元加到q个内存块的MemoryBlock所l护的自由分配单元链表的头部Q同时将其nFree值递增1。回收后Q考虑到资源的有效利用及后l操作的性能Q内存池的操作会l箋判断Q如果此内存块的所有分配单元都是自qQ那么这个内存块׃从MemoryPool中被Udq作Z个整体返回给q程堆;如果该内存块中还有非自由分配单元Q这时不能将此内存块q回l进E堆。但是因为刚刚有一个分配单元返回给了这个内存块Q即q个内存块有自由分配单元可供下次分配Q因此它会被UdMemoryPooll护的内存块的头部。这样下ơ的内存h到来QMemoryPool遍历其内存块链表以寻找自由分配单元时Q第1ơ寻扑ְ会找到这个内存块。因个内存块实有自由分配单元,q样可以减少MemoryPool的遍历次数?/p> <p>lg所qͼ每个内存池(MemoryPoolQ维护一个内存块链表Q单链表Q,每个内存块由一个维护该内存块信息的块头l构QMemoryBlockQ和多个分配单元l成Q块头结构MemoryBlock则进一步维护一个该内存块的所有自由分配单元组成的"链表"。这个链表不是通过"指向下一个自由分配单元的指针"链接h的,而是通过"下一个自由分配单元的~号"链接hQ这个编号值存储在该自由分配单元的头两个字节中。另外,W?个自由分配单元的起始位置q不是MemoryBlockl构?后面?W?个地址位置Q而是MemoryBlockl构?内部"的最后一个字节aDataQ也可能不是最后一个,因ؓ考虑到字节对齐的问题Q,卛_配单元实际上往前面错了一位。又因ؓMemoryBlockl构体后面的I间刚好是分配单元的整数倍,q样依次错位下去Q内存块的最后一个字节实际没有被利用。这么做的一个原因也是考虑C同^台的UL问题Q因Z同^台的寚w方式可能不尽相同。即当申请MemoryBlock大小内存Ӟ可能会返回比其所有成员大dq要大一些的内存。最后的几个字节是ؓ?补齐"Q而?aData成ؓW?个分配单元的起始位置Q这样在寚w方式不同的各U^C都可以工作?/p> <p><a name=N101F6><span id="x9l9tzr" class=smalltitle>6.2.3 l节剖析</span></a></p> <p>有了上述的M印象后,本节来仔l剖析其实现l节?/p> <p>Q?QMemoryPool的构造如下:</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 > 4 ) nUnitSize = (_nUnitSize + (MEMPOOL_ALIGNMENT-1)) & ~(MEMPOOL_ALIGNMENT-1); ? else if ( _nUnitSize <= 2 ) nUnitSize = 2; ? else nUnitSize = 4; } </pre> </td> </tr> </tbody> </table> <br> <p>从①处可以看出,MemoryPool创徏Ӟq没有立d建真正用来满_存申L内存块,卛_存块链表刚开始时为空?/p> <p>②处和③处分别设|?W?ơ创建的内存块所包含的分配单元的个数"Q及"随后创徏的内存块所包含的分配单元的个数"Q这两个值在MemoryPool创徏旉过参数指定Q其后在该MemoryPool对象生命周期中一直不变?/p> <p>后面的代码用来设|nUnitSizeQ这个值参考传入的_nUnitSize参数。但是还需要考虑两个因素。如前所qͼ每个分配单元在自q态时Q其头两个字节用来存?其下一个自由分配单元的~号"。即每个分配单元"最??两个字节"Q这是⑤处赋值的原因。④处是大?个字节的大小_nUnitSize往?取整?大于_nUnitSize的最的MEMPOOL_ ALIGNMENT的倍数Q前提是MEMPOOL_ALIGNMENT?的倍数Q。如_nUnitSize?1 ӞMEMPOOL_ALIGNMENT?QnUnitSize?6QMEMPOOL_ALIGNMENT?QnUnitSize?12QMEMPOOL_ALIGNMENT?QnUnitSize?2Q依ơ类推?/p> <p>Q?Q当向MemoryPool提出内存hӞ</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 ) ? { …… } MemoryBlock* pMyBlock = pBlock; while (pMyBlock && !pMyBlock->nFree )? pMyBlock = pMyBlock->pNext; if ( pMyBlock ) ? { char* pFree = pMyBlock->aData+(pMyBlock->nFirst*nUnitSize); pMyBlock->nFirst = *((USHORT*)pFree); pMyBlock->nFree--; return (void*)pFree; } else ? { if ( !nGrowSize ) return NULL; pMyBlock = new(nGrowSize, nUnitSize) FixedMemBlock(nGrowSize, nUnitSize); if ( !pMyBlock ) return NULL; pMyBlock->pNext = pBlock; pBlock = pMyBlock; return (void*)(pMyBlock->aData); } } </pre> </td> </tr> </tbody> </table> <br> <p>MemoryPool满内存h的步骤主要由四步l成?/p> <p>①处首先判断内存池当前内存块链表是否为空Q如果ؓI,则意味着q是W?ơ内存申误求。这Ӟ从进E堆中申请一个分配单元个CؓnInitSize的内存块Qƈ初始化该内存块(主要初始化MemoryBlockl构体成员,以及创徏初始的自由分配单元链表,下面会详l分析其代码Q。如果该内存块申h功,q初始化完毕Q返回第1个分配单元给调用函数。第1个分配单元以MemoryBlockl构体内的最后一个字节ؓ起始地址?/p> <p>②处的作用是当内存池中已有内存块Q即内存块链表不为空Q时遍历该内存块链表Q寻找还?自由分配单元"的内存块?/p> <p>③处查如果找到还有自由分配单元的内存块,?定位"到该内存块现在可以用的自由分配单元处?定位"?MemoryBlockl构体内的最后一个字节位|aDatav始位|,以MemoryPool的nUnitSize为步长来q行。找到后Q需要修?MemoryBlock的nFree信息Q剩下来的自由分配单元比原来减少了一个)Q以及修Ҏ内存块的自由存储单元链表的信息。在扑ֈ的内存块中,pMyBlock->nFirst内存块中自由存储单元链表的表_其下一个自由存储单元的~号存放?pMyBlock->nFirst指示的自由存储单元(亦即刚才定位到的自由存储单元Q的头两个字节。通过刚才定位到的位置Q取其头两个字节的|赋给pMyBlock->nFirstQ这是此内存块的自由存储单元链表的新的表头Q即下一ơ分配出ȝ自由分配单元的编P如果nFree大于零的话)。修改维护信息后Q就可以刚才定位到的自由分配单元的地址q回l此ơ申L调用函数。注意,因ؓq个分配单元已经被分配,而内存块无须l护已分配的分配单元Q因此该分配单元的头两个字节的信息已l没有用处。换个角度看Q这个自由分配单元返回给调用函数后,调用函数如何处置q块内存Q内存池无从知晓Q也无须知晓。此分配单元在返回给调用函数Ӟ其内容对于调用函数来说是无意义的。因此几乎可以肯定调用函数在用这个单元的内存时会覆盖其原来的内容Q即头两个字节的内容也会被抹厅R因此每个存储单元ƈ没有因ؓ需要链接而引入多余的l护信息Q而是直接利用单元内的头两个字节,当其分配后,头两个字节也可以被调用函数利用。而在自由状态时Q则用来存放l护信息Q即下一个自由分配单元的~号Q这是一个有效利用内存的好例子?/p> <p>④处表示在②处遍历时Q没有找到还有自由分配单元的内存块,q时Q需要重新向q程堆申请一个内存块。因Z是第一ơ申请内存块Q所以申L内存块包含的分配单元个数为nGrowSizeQ而不再是nInitSize。与①处相同Q先做这个新甌内存块的初始化工作,然后此内存块插入MemoryPool的内存块链表的头部,再将此内存块的第1个分配单元返回给调用函数。将此新内存块插入内存块链表的头部的原因是该内存块还有很多可供分配的自由分配单元Q除非nGrowSize{于1Q这应该不太可能。因为内存池的含义就是一ơ性地从进E堆中申请一大块内存Q以供后l的多次甌Q,攑֜头部可以使得在下ơ收到内存申hQ减②处对内存块的遍历旉?/p> <p>可以用图6-2的MemoryPool来展CMemoryPool::Alloc的过E。图6-3是某个时刻MemoryPool的内部状态?/p> <br><a name=N10234><strong>?-3 某个时刻MemoryPool的内部状?/strong></a><br><img border=0 alt="?-3 某个时刻MemoryPool的内部状? src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_3.gif" width=568 height=397> <br> <p>因ؓMemoryPool的内存块链表不ؓI,因此会遍历其内存块链表。又因ؓW?个内存块里有自由的分配单元,所以会从第1个内存块中分配。检查nFirstQ其gؓmQ这时pBlock->aData+(pBlock->nFirst*nUnitSize) 定位到编号ؓm的自由分配单元的起始位置Q用pFree表示Q。在q回pFree之前Q需要修Ҏ内存块的l护信息。首先将nFree递减1Q然后取?pFree处开始的头两个字节的|需要说明的是,q里aData处gؓk。其实不是这一个字节。而是以aData和紧跟其后的另外一个字节合在一h成的一个USHORT的|不可误会Q。发CؓkQ这时修改pBlock的nFirst为k。然后,q回pFree。此时MemoryPool的结构如?6-4所C?/p> <br><a name=N10249><strong>?-4 MemoryPool的结?/strong></a><br><img border=0 alt="?-4 MemoryPool的结? src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_4.gif" width=521 height=373> <br> <p>可以看到Q原来的W?个可供分配的单元Qm~号处)已经昄分配的状态。而pBlock的nFirst已经指向原来m单元下一个自由分配单元的~号Q即k?/p> <p>Q?QMemoryPool回收内存Ӟ</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 ) { …… MemoryBlock* pMyBlock = pBlock; while ( ((ULONG)pMyBlock->aData > (ULONG)pFree) || ((ULONG)pFree >= ((ULONG)pMyBlock->aData + pMyBlock->nSize)) )? { …… } pMyBlock->nFree++; ? *((USHORT*)pFree) = pMyBlock->nFirst; ? pMyBlock->nFirst = (USHORT)(((ULONG)pFree-(ULONG)(pBlock->aData)) / nUnitSize);? if (pMyBlock->nFree*nUnitSize == pMyBlock->nSize )? { …… } else { …… } } </pre> </td> </tr> </tbody> </table> <br> <p>如前所qͼ回收分配单元Ӟ可能会将整个内存块返回给q程堆,也可能将被回收分配单元所属的内存块移臛_存池的内存块链表的头部。这两个操作都需要修攚w表结构。这旉要知道该内存块在链表中前一个位|的内存块?/p> <p>①处遍历内存池的内存块链表,定该待回收分配单元QpFreeQ落在哪一个内存块的指针范围内Q通过比较指针值来定?/p> <p>q行到②处,pMyBlockx到的包含pFree所指向的待回收分配单元的内存块Q当Ӟq时应该q需要检?pMyBlock为NULL时的情ŞQ即pFree不属于此内存池的范围Q因此不能返回给此内存池Q读者可以自行加上)。这时将pMyBlock?nFree递增1Q表C此内存块的自由分配单元多了一个?/p> <p>③处用来修改该内存块的自由分配单元链表的信息Q它这个待回收分配单元的头两个字节的值指向该内存块原来的W一个可分配的自由分配单元的~号?/p> <p>④处pMyBlock的nFirst值改变ؓ指向q个待回收分配单元的~号Q其~号通过计算此单元的起始位置相对pMyBlock的aData位置的差|然后除以步长QnUnitSizeQ得到?/p> <p>实质上,③和④两步的作用是此待回收分配单?真正回收"。值得注意的是Q这两步实际上是使得此回收单元成为此内存块的下一个可分配的自由分配单元,卛_它放在了自由分配单元链表的头部。注意,其内存地址q没有发生改变。实际上Q一个分配单元的内存地址无论是在分配后,q是处于自由状态时Q一直都不会变化。变化的只是其状态(已分?自由Q,以及当其处于自由状态时在自由分配单元链表中的位|?/p> <p>⑤处查当回收完毕后,包含此回收单元的内存块的所有单元是否都处于自由状态,且此内存是否处于内存块链表的头部。如果是Q将此内存块整个的返回给q程堆,同时修改内存块链表结构?/p> <p>注意Q这里在判断一个内存块的所有单元是否都处于自由状态时Qƈ没有遍历其所有单元,而是判断nFree乘以 nUnitSize是否{于nSize。nSize是内存块中所有分配单元的大小Q而不包括头部MemoryBlockl构体的大小。这里可以看到其用意Q即用来快速检查某个内存块中所有分配单元是否全部处于自q态。因为只需l合nFree和nUnitSize来计得出结论,而无遍历和计算所有自q态的分配单元的个数?/p> <p>另外q需注意的是Q这里ƈ不能比较nFree与nInitSize或nGrowSize的大来判断某个内存块中所有分配单元都q态,q是因ؓW?ơ分配的内存块(分配单元个数为nInitSizeQ可能被Ud链表的后面,甚至可能在移到链表后面后Q因为某个时间其所有单元都处于自由状态而被整个q回l进E堆。即在回收分配单元时Q无法判定某个内存块中的分配单元个数到底是nInitSizeq是nGrowSizeQ也无法通过比较nFree与nInitSize或nGrowSize的大来判断一个内存块的所有分配单元是否都q态?/p> <p>以上面分配后的内存池状态作Z子,假设q时W?个内存块中的最后一个单元需要回Ӟ已被分配Q假讑օ~号为mQpFree指针指向它)Q如?-5所C?/p> <p>不难发现Q这时nFirst的值由原来?变ؓm。即此内存块下一个被分配的单元是m~号的单元,而不?~号的单元(最先分配的是最新回收的单元Q从q一点看Q这个过E与栈的原理cMQ即先进后出。只不过q里?q?意味着"回收"Q??则意味着"分配"Q。相应地Qm?下一个自由单?标记?Q即内存块原来的"下一个将被分配出ȝ单元"Q这也表明最q回收的分配单元被插C内存块的"自由分配单元链表"的头部。当ӞnFree递增1?/p> <br><a name=N1028B><strong>?-5 分配后的内存池状?/strong></a><br><img border=0 alt="?-5 分配后的内存池状? src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_5.gif" width=458 height=328> <br> <p>处理至⑥处之前,其状态如?-6所C?/p> <br><a name=N102A0><strong>?-6 处理至⑥处之前的内存池状?/strong></a><br><img border=0 alt="?-6 处理至⑥处之前的内存池状? src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_6.gif" width=535 height=365> <br> <p>q里需要注意的是,虽然pFree?回收"Q但是pFree仍然指向m~号的单元,q个单元在回收过E中Q其头两个字节被覆写Q但其他部分的内容ƈ没有改变。而且从整个进E的内存使用角度来看Q这个m~号的单元的状态仍然是"有效?。因里的"回收"只是回收l了内存池,而ƈ没有回收l进E堆Q因此程序仍然可以通过pFree讉K此单元。但是这是一个很危险的操作,因ؓ首先该单元在回收q程中头两个字节已被覆写Qƈ且该单元可能很快׃被内存池重新分配。因此回收后通过pFree指针对这个单元的讉K都是错误的,L作会d错误的数据,写操作则可能会破坏程序中其他地方的数据,因此需要格外小心?/p> <p>接着Q需要判断该内存块的内部使用情况Q及其在内存块链表中的位|。如果该内存块中省略?……"所表示的其他部分中q有被分配的单元Q即nFree乘以nUnitSize不等于nSize。因为此内存块不在链表头Q因此还需要将其移到链表头部,如图6-7所C?/p> <br><a name=N102B8><strong>?-7 因回收引LMemoryBlockUd</strong></a><br><img border=0 alt="?-7 因回收引LMemoryBlockUd" src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_7.gif" width=508 height=333> <br> <p>如果该内存块中省略号"……"表示的其他部分中全部都是自由分配单元Q即nFree乘以nUnitSize{于nSize。因为此内存块不在链表头Q所以此旉要将此内存块整个回收l进E堆Q回收后内存池的l构如图6-8所C?/p> <br><a name=N102CD><strong>?-8 回收后内存池的结?/strong></a><br><img border=0 alt="?-8 回收后内存池的结? src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_8.gif" width=322 height=346> <br> <p>一个内存块在申请后会初始化Q主要是Z建立最初的自由分配单元链表Q下面是其详l代码:</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 < nTypes; i++) ? { *reinterpret_cast<USHORT*>(pData) = i; ? pData += nUnitSize; } } </pre> </td> </tr> </tbody> </table> <br> <p>q里可以看到Q①处pData的初值是aDataQ即0~号单元。但是②处的循环中i却是?开始,然后在@环内部的③处pData的头两个字节值置为i。即0号单元的头两个字节gؓ1Q?号单元的头两个字节gؓ2Q一直到QnTypes-2Q号单元的头两个字节gؓQnTypes-1Q。这意味着内存块初始时Q其自由分配单元链表是从0号开始。依ơ串联,一直到倒数W?个单元指向最后一个单元?/p> <p>q需要注意的是,在其初始化列表中QnFree初始化ؓnTypes-1Q而不是nTypesQ,nFirst初始化ؓ 1Q而不?Q。这是因为第1个单元,?~号单元构造完毕后Q立M被分配。另外注意到最后一个单元初始ƈ没有讄头两个字节的|因ؓ该单元初始在本内存块中ƈ没有下一个自由分配单元。但是从上面例子中可以看刎ͼ当最后一个单元被分配q回收后Q其头两个字节会被设|?/p> <p>?-9所CZؓ一个内存块初始化后的状态?/p> <br><a name=N102F4><strong>?-9 一个内存块初始化后的状?/strong></a><br><img border=0 alt="?-9 一个内存块初始化后的状? src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_9.gif" width=199 height=327> <br> <p>当内存池析构Ӟ需要将内存池的所有内存块q回l进E堆Q?/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 ) { …… } } </pre> </td> </tr> </tbody> </table> <br> <p><a name=N10310><span id="rj7t779" class=smalltitle>6.2.4 使用Ҏ</span></a></p> <p>分析内存池的内部原理后,本节说明如何使用它。从上面的分析可以看刎ͼ该内存池主要有两个对外接口函敎ͼ即Alloc?Free。Allocq回所甌的分配单元(固定大小内存Q,Free则回收传入的指针代表的分配单元的内存l内存池。分配的信息则通过 MemoryPool的构造函数指定,包括分配单元大小、内存池W?ơ申L内存块中所含分配单元的个数Q以及内存池后箋甌的内存块所含分配单元的个数{?/p> <p>lg所qͼ当需要提高某些关键类对象的申P回收效率Ӟ可以考虑该cL有生成对象所需的空间都从某个这L内存池中开辟。在销毁对象时Q只需要返回给该内存池?一个类的所有对象都分配在同一个内存池对象?q一需求很自然的设计方法就是ؓq样的类声明一个静态内存池对象Q同时ؓ了让其所有对象都从这个内存池中开辟内存,而不是缺省的从进E堆中获得,需要ؓ该类重蝲一个newq算W。因为相应地Q回收也是面向内存池Q而不是进E的~省堆,q需要重载一个deleteq算W。在newq算W中用内存池的Alloc函数满所有该cd象的内存hQ而销毁某对象则可以通过?deleteq算W中调用内存池的Free完成?/p> <p><a name=N1031C><span id="9bxbx9r" class=smalltitle>6.2.5 性能比较</span></a></p> <p>Z试利用内存池后的效果,通过一个很的试E序可以发现采用内存池机制后耗时?97 ms。而没有采用内存池机制则耗时625 msQ速度提高?2.48%。速度提高的原因可以归lؓ几点Q其一Q除了偶的内存甌和销毁会D从进E堆中分配和销毁内存块外,l大多数的内存申请和销毁都由内存池在已l申请到的内存块中进行,而没有直接与q程堆打交道Q而直接与q程堆打交道是很耗时的操作;其二Q这是单U程环境的内存池Q可以看到内存池的Alloc和Free操作中ƈ没有加线E保护措施。因此如果类A用到该内存池Q则所有类A对象的创建和销毁都必须发生在同一个线E中。但如果cA 用到内存池,cB也用到内存池Q那么类A的用线E可以不必与cB的用线E是同一个线E?/p> <p>另外Q在W?章中已经讨论q,因ؓ内存池技术得同cd的对象分布在盔R的内存区域,而程序会l常对同一cd的对象进行遍历操作。因此在E序q行q程中发生的~页应该会相应少一些,但这个一般只能在真实的复杂应用环境中q行验证?/p> <div id="779xjv9" class=ibm-alternate-rule></div> <p class="ibm-ind-link ibm-back-to-top"><a class=ibm-anchor-up-link ><u><font color=#0066cc>回页?/font></u></a></p> <p><a name=N10328><span id="t9x7zh1" class=atitle>6.3 本章结</span></a></p> <p>内存的申请和释放对一个应用程序的整体性能影响极大Q甚臛_很多时候成为某个应用程序的瓉。消除内存申请和释放引v的瓶颈的Ҏ往往是针对内存用的实际情况提供一个合适的内存池。内存池之所以能够提高性能Q主要是因ؓ它能够利用应用程序的实际内存使用场景中的某些"Ҏ?。比如某些内存申请与释放肯定发生在一个线E中Q某U类型的对象生成和销毁与应用E序中的其他cd对象要频J得多,{等。针对这些特性,可以些特D的内存使用场景提供量n定做的内存池。这栯够消除系l提供的~省内存机制中,对于该实际应用场景中的不必要的操作,从而提升应用程序的整体性能?/p> <img src ="http://www.shnenglu.com/guojingjia2006/aggbug/143473.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/guojingjia2006/" target="_blank">果?/a> 2011-04-05 20:18 <a href="http://www.shnenglu.com/guojingjia2006/archive/2011/04/05/143473.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c++ 内存泄露(?http://www.shnenglu.com/guojingjia2006/archive/2011/04/05/143472.html果?/dc:creator>果?/author>Tue, 05 Apr 2011 12:11:00 GMThttp://www.shnenglu.com/guojingjia2006/archive/2011/04/05/143472.htmlhttp://www.shnenglu.com/guojingjia2006/comments/143472.htmlhttp://www.shnenglu.com/guojingjia2006/archive/2011/04/05/143472.html#Feedback2http://www.shnenglu.com/guojingjia2006/comments/commentRss/143472.htmlhttp://www.shnenglu.com/guojingjia2006/services/trackbacks/143472.html 内存泄露怿对C++E序员来说都不陌生。解军_存泄露的Ҏ多种多样Q大部分Ҏ以追t检ؓ主,q种Ҏ实现hҎQ用方便,也比较安全?/p>

         首先我们要确定这个模块的主要功能Q?/p>

  1. 能追t内存的分配和释放过E?/li>
  2. 要能昄内存分配的相关信息,比如内存块大,代码所在文件所在行{?/li>
  3. 在发现内存泄露时及时l出相关信息?/li>
  4. 能正处理一些异常情况,比如内存不Q对象初始化p|{等?/li>
  5. 是线E安全的。[*q个q没有实现]

        有了一些基本功能需求,我们需要考虑每种功能怎么d现。首先,我们可以通过重蝲的方式来q踪new,delete.malloc和freeQC++l我提供了这LҎ。因为本文主要针对C++Q所以主要讲重蝲new,delete的方法,malloc和free的重载实C此类|最l版本的E序中也实现了malloc和free的重载?a id=more>

1.重蝲new和delete

        首先我们要了解一下new和delete是怎么工作的。C++中的操作W最l都会被转换成函数Ş式,例如"new int"会变?opetaor new(sizeof(int))"Q?new double[10]"会变?operator new(sizeof(double)*10)"Q同?#8220;delete p”变成了"operator delete(p)"。另外一个需要特别注意的地方是,new对于用户定义的数据类型(即你的自定义c)会自动调用该cd的构造函敎ͼ如果构造函数没有抛出异常,则正分配,否则会中断分配操作,异怼递给用户。默认情况下Qnew可以对象构造异常进行捕莗另外一个版本的new是不带捕获异常功能的的了,所以C++pȝ提供的new和delete有:

1
2
3
4
5
6
7
8
9
void* operator new(size_t size)throw(std::bad_alloc);
void* operator new[](size_t size) throw(std::bad_alloc);
void* operator new(size_t,std::nothrow_t&)throw();
void* operator new[](size_t,std::nothrow_t&)throw();
 
void  operator delete(void* pointer);
void  operator delete[](void* pointer);
void  operator delete(void* pointer,std::nothrow_t&);
void  operator delete[](void* pointer,std::nothrow_t&);<br>

        其中Qnothrow_t是一个空l构?#8220;struct nothrow_t{}"Q它的一个实例就是nothrowQC++用它来区分可以捕获异常的new和不可捕获异常的new。我们不能直接修改内部函数的行ؓQ但是我们可以重载它们。ؓ了实现提供内存分配信息的功能Q我们给重蝲的函数加上几个参数。得C下函敎ͼ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void* operator new(size_t size);
void* operator new[](size_t size);
void* operator new(size_t,std::nothrow_t&)throw();
void* operator new[](size_t,std::nothrow_t&)throw();
void* operator new(size_t size,const char* file,const char* func,const int line)throw(std::bad_alloc);
void* operator new[](size_t size,const char* file,const char* func,const int line) throw(std::bad_alloc);
void* operator delete(void* pointer);
void* operator delete[](void* pointer);
/*******Placement Delete********/
void  operator delete(void* pointer,const char* file,const char* func,const int line);
void  operator delete[](void* pointer,const char* file,const char* func,const int line);
void  operator delete(void* pointer,std::nothrow_t&);
void  operator delete[](void* pointer,std::nothrow_t&);
/*******************************/

         中间的几个函敎ͼ是我们主要需要重载的函数Q模块的大部分工作也都由着几个函数完成。这些函数参CQfile表示分配代码所在的文g名,func表示代码所在的函数名,line表示代码行号。这几个参数信息我们可以通过~译器预定义好的几个宏来获得Q__FILE__,__FUNCTION__,__LINE__。也是说可以将"new ..."替换?new(__FILE__,__FUNCTION__,__LINE__) ..."Q最l成?operator new(sizeof(...),__FILE__,__FUNCTION__,__LINE__)"的Ş式,也就辑ֈ了我们的目的。关?placement delete在下面详细解释?/p>

2.I间分配

        接下来我们要考虑内存分配信息的组l问题了。我们先来了解一下编译器是怎么l织的。在大部分编译器中,new所分配的空间都要大于实际申LI间Q大出来的部分就是编译器定义的内存块的信息,包括了内存块的大还有一些其他信息。如下图所C:

        我们把包含内存分配信息的部分叫做cookie数据。ؓ了方便,我们把cookie数据攑֜分配的内存的起始位置Q之后紧接有效数据区。我们还需要把q回l调用者的指针和new分配的数据区联系hQ原本想用性能比较好的STL的map数据l构来储存这些数据,但是map内部同样也用new来分配内存,所以如果直接用map来储存,׃陷入d@环中。所以这里我们必自q实一个数据结构。我们可以对q回l调用者的地址q行HashQ得到hash 表中的地址Q具有相同Hash值的数据我们用一个单向链表连接v来。最l的数据l构如下图所C:

2.1.构造函C的异?/strong>

        另外一个必要注意的一ҎQnew操作W会先分配空间然后调用用戯定义cd的构造函敎ͼ如果构造函数抛出异常,需要用h动释攑ַ分配的内存。问题在于释放这L内存不能用一般的delete操作W,可以用一个例子来说明Q?/p>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
#include <stdexcept>
 
void* operator new(size_t size, int line) {
    printf("Allocate %u bytes on line %d\\n", size, line);
    return operator new(size);
}
 
class UserClass {
public:
    UserClass(int n)throw(){
        if(n<=0){
             throw std::runtime_error("n must be positive");
        }
    }
};
 
int main(){
    try{
        UserClass* myobj=new(__LINE__) UserClass(-10);
        delete myobj; //doesn't work if placement was not defined
    } catch(const std::runtime_error& e) {
        fprintf(stderr,"Exception: %s\n",e.what());
    }
    return 0;
}<br>

        q里Q虽然在newq后试图使用delete释放已经分配的内存,但是实际上不会释放。也怽的编译器会给样一条消息:

        “no matching operator delete found”

        Z正确处理q种情况Qƈl用h供相关的信息Q我们需要定义placement delete操作W。placement delete是C++98标准中才有的一个特性,所以对于某些老的~译器(大致可以认ؓ是指那些98q以前编写的~译器)不支持这个特性。这需要在模块中添加宏定义让用户可以关闭placement delete的定义,以便模块能在较老的~译器上~译。以下就是需要定义的placement delete操作W:

1
2
3
4
void  operator delete(void* pointer,const char* file,const char* func,const int line);
void  operator delete[](void* pointer,const char* file,const char* func,const int line);
void  operator delete(void* pointer,std::nothrow_t&);
void  operator delete[](void* pointer,std::nothrow_t&);<br>

3.查内存泄?/strong>

        有了上面的实玎ͼ我们可以方便的手动检内存泄霌Ӏ通过一个函数来实现Q它会检索整个hash表,如果表不为空则存在内存泄霌Ӏ?/p>

        Z辑ֈ在最后程序退出时查内存泄露的目的Q我们需要在所有对象调用析构函数后q行内存泄露,q是因ؓ某些用户cd在构造函数里调用new而在析构函数里调用delete。这样做能大大的减小误报的概率。而且因ؓ对象的析构函数的调用往往在主函数main()执行l束之后q行Q所以我们也不能直接在主函数里进行内存泄露检。这里我们利用一个全局对象来实现这U检。首先我们定义一个类Q?/p>

1
2
3
4
5
6
7
8
9
10
11
class MemCheck{
    public:
        MemCheck(){
            memset(pTable,0,sizeof(mc_block_node_t*) * MC_HASHTABLESIZE);
        }
        ~MemCheck(){
            if(mc_checkmem()){
                abort();
            }
        }
};

        q里的构造函数初始化Hash表。析构函数检内存泄霌Ӏ然后定义一个MemCheck的全局静态对象,q样当程序运行之前会初始化hash表,E序退出时内存泄霌Ӏ可是问题又来了Q如果一个程序中有多个全局静态对象会怎样Q不q的是,对于全局静态对象的构造顺序和析构序是C++标准中的一个未定义问题Q也是_q个序取决于编译器的具体实现。考虑Q绝大多数^C用VC和GCC~译器,我们可以针对q两U编译器来控制全局对象的构造和解析序?/p>

1
2
3
4
5
6
7
8
9
#ifdef _MSC_VER
#pragma init_seg(lib)
#endif
 
static MemCheck mc_autocheck_object
#ifdef __GNUC__
__attribute__((init_priority (101)))
#endif
;

        q里的宏定义部分都是~译器的选项?/p>

]]>
PE学习ȝhttp://www.shnenglu.com/guojingjia2006/archive/2010/10/12/129621.html果?/dc:creator>果?/author>Tue, 12 Oct 2010 09:22:00 GMThttp://www.shnenglu.com/guojingjia2006/archive/2010/10/12/129621.htmlhttp://www.shnenglu.com/guojingjia2006/comments/129621.htmlhttp://www.shnenglu.com/guojingjia2006/archive/2010/10/12/129621.html#Feedback0http://www.shnenglu.com/guojingjia2006/comments/commentRss/129621.htmlhttp://www.shnenglu.com/guojingjia2006/services/trackbacks/129621.html#include "windows.h"#include <iostream>using namespace std;#define NTSI...  阅读全文

]]>
__type_traits(?http://www.shnenglu.com/guojingjia2006/archive/2010/10/11/129405.html果?/dc:creator>果?/author>Mon, 11 Oct 2010 01:24:00 GMThttp://www.shnenglu.com/guojingjia2006/archive/2010/10/11/129405.htmlhttp://www.shnenglu.com/guojingjia2006/comments/129405.htmlhttp://www.shnenglu.com/guojingjia2006/archive/2010/10/11/129405.html#Feedback0http://www.shnenglu.com/guojingjia2006/comments/commentRss/129405.htmlhttp://www.shnenglu.com/guojingjia2006/services/trackbacks/129405.html在STL中ؓ了提供通用的操作而又不损失效率,我们用到了一U特D的技巧,叫traits~程技巧。具体的来说Qtraits是 通过定义一些结构体或类Qƈ利用模板cȝ化和偏特化的能力Q给cd赋予一些特性,q些Ҏ根据类型的不同而异。在E序设计中可以用这些traits来判 断一个类型的一些特性,引发C++的函数重载机Ӟ实现同一U操作因cd不同而异的效果。traits的编E技巧极度I补了C++语言的不??/strong>


举例Q?br>
现在定义一个__type_traits可以获得cd的如下属性:
1. 是否存在non-trivial default constructor
2. 是否存在non-trivial copy constructor
3. 是否存在non-trivial assignment operator
4. 是否存在non-trivial destructor

struct __true_type {
};
struct __false_type {
};

template <class _Tp>
struct __type_traits {

   typedef __false_type    has_trivial_default_constructor;
   typedef __false_type    has_trivial_copy_constructor;
   typedef __false_type    has_trivial_assignment_operator;
   typedef __false_type    has_trivial_destructor;
};


问题Qؓ什么把对象的所有的属性都定义为__false_typeQ?br> q样是采用最保守的做法,先把所有的对象属性都讄为__false_typeQ然后在针对每个基本数据cd设计特化的__type_traitsQ就可以辑ֈ预期的目的,如可以定义__type_traits<int>如下Q?br>
template <>
struct __type_traits<int> {
   typedef __true_type    has_trivial_default_constructor;
   typedef __true_type    has_trivial_copy_constructor;
   typedef __true_type    has_trivial_assignment_operator;
   typedef __true_type    has_trivial_destructor;
};

template <>
struct __type_traits<char> {
   typedef __true_type    has_trivial_default_constructor;
   typedef __true_type    has_trivial_copy_constructor;
   typedef __true_type    has_trivial_assignment_operator;
   typedef __true_type    has_trivial_destructor;
};

    ......

    ......


其他基本cd的traits也可以有相应的定?br>
__type_traits的偏特化版本
template <class _Tp>
struct __type_traits<_Tp*> {
   typedef __true_type    has_trivial_default_constructor;
   typedef __true_type    has_trivial_copy_constructor;
   typedef __true_type    has_trivial_assignment_operator;
   typedef __true_type    has_trivial_destructor;
   typedef __true_type    is_POD_type;
};

我们可以自定义__type_traits的特化版?br> 比如对与自定义的ShapecdQ我们可以这样定义__type_traits<Shape>
struct __type_traits<Shape> {
   typedef __false_type    has_trivial_default_constructor;
   typedef __true_type    has_trivial_copy_constructor;
   typedef __true_type    has_trivial_assignment_operator;
   typedef __true_type    has_trivial_destructor;
   typedef __true_type    is_POD_type;
};

如果~译器够厉害Q我们甚臛_以不用自己去定义特化的__type_traitsQ编译器p够帮我们搞定Q)

如何使用呢?

假设现在用个模板函数fun需要根据类型T是否有non-trivial constructor来进行不同的操作Q可以这h实现Q?br>
template<class T>
void fun()
{
     typedef typename __type_traits<T>::has_trivial_constructor _Trivial_constructor;
    __fun(_Trivial_constructor()); // Ҏ得到的_Trivial_constructor来调用相应的函数
}

// 两个重蝲的函?br> void _fun(_true_type)
{
cout<<"fun(_true_type)called"<<endl;
}
void _fun(_false_type)
{
cout<<"fun(_false_type) called"<<endl;
}

//试代码

int main()
{
fun<char>();
fun<int>();
fun<char *>();
fun<double>();
}



]]>
Traits学习--q代?1)http://www.shnenglu.com/guojingjia2006/archive/2010/10/09/129184.html果?/dc:creator>果?/author>Sat, 09 Oct 2010 05:23:00 GMThttp://www.shnenglu.com/guojingjia2006/archive/2010/10/09/129184.htmlhttp://www.shnenglu.com/guojingjia2006/comments/129184.htmlhttp://www.shnenglu.com/guojingjia2006/archive/2010/10/09/129184.html#Feedback0http://www.shnenglu.com/guojingjia2006/comments/commentRss/129184.htmlhttp://www.shnenglu.com/guojingjia2006/services/trackbacks/129184.html
用template要求写一个模板函敎ͼq回D求是参数cdQ初步设?br>template<typename T>
class AIter{
public:
    AIter(T
* p=0):ptr(p){};
    T
* ptr;
    typedef T value_type;
    T
& operator*()const{
        
return *ptr;
    }
    T
* operator->()const{
        
return ptr;
    }
};
template
<typename T>
typename T::value_type
func(T val){
    
return *val;
}

q方法一个缺陷就是对于不是class type的类型无能ؓ?比如原生指针,只有class typecd才能内嵌cd

改进--模板偏特?template partial specialization)
声明一个类?br>template<typename T>
struct stl_iterator_traits{
    typedef typename T::value_type value_type;
};
原先的func可以写成q样
template<typename T>
typename stl_iterator_traits<T>::value_type
func(T val){
    return *val;
}
q样q是处理不了
int* p=new int(3);
func(p);
原生指针cdQؓ其提供特化版?br>template<typename T>
struct stl_iterator_traits<T*>{
    typedef T value_type;
};
q样p完美解决刚才问题

但是对于指向常数对象的指?br>stl_iterator_traits<const int*>::value_type
我们希望暂时存储一个变量,但是我们获取的类型是const int,声明一个无法赋值的临时变量无意义,所以我们在提供一个特化版?br>
template<typename T>
struct stl_iterator_traits<const T*>{
    typedef T value_type;
};
iterator example:
#include <iterator>
//#using <mscorlib.dll>
#include <iostream>
#include 
<memory>
#include 
<vector>
#include 
<algorithm>
//using namespace System;
using namespace std;

template
<typename T>
class ListItem{
public:
    ListItem(T value){
        _value
=value;
        _next
=NULL;
    }
    ListItem(){
        _next
=NULL;
        _value
=0;
    }
    T value()
const{
        
return _value;
    }
    ListItem
<T>* _next;
    T _value;    
};
template
<class Item>
class ListIter:public iterator<std::forward_iterator_tag,Item>{
public:
    Item
* ptr;
    ListIter(Item
* p=0):ptr(p){};
    Item
& operator*()const{
        
return *ptr;
    }
    Item
* operator->()const{
        
return ptr;
    }
    ListIter
& operator++(){
        ptr
=ptr->_next;
        
return *this;
    }
    ListIter 
operator++(int){
        ListIter tmp
=*this;
        
++(*this);
        
return tmp;
    }
    
bool operator==(const ListIter& iter)const{
        
return ptr==iter.ptr;
    }
    
bool operator!=(const ListIter& iter)const{
        
return ptr!=iter.ptr;
    }
};
template
<typename T>
bool operator==(ListItem<T>& item,T value){
    
return item.value()==value;
}

template
<typename T>
class List{
public:
    typedef ListIter
<ListItem<T> > iterator;
    List(){
        _end
=new ListItem<T>();
        _front
=0;
    }
    
void insert_front(T value){
        ListItem
<T>* item=new ListItem<T>(value);
        
if(empty()){
            item
->_next=_end;
            _front
=item;
        }
else{
            item
->_next=_front;
            _front
=item;
        }
    };
    
bool empty(){
        
return _front==NULL;
    }
    
void insert_end(T value){
        
//ListItem<T>* item=new ListItem<T>(value);
        if(empty()){
            _front
=_end;
            _end
->_value=value;
            _end
->_next=new ListItem<T>();
            _end
=_end->_next;
        }
else{
            _end
->_value=value;
            _end
->_next=new ListItem<T>();
            _end
=_end->_next;
        }
    };
    
void display(ostream& os=cout){
        ListItem
<T>* head=_front;
        
while(head!=_end){
            cout
<<head->value()<<endl;
            head
=head->_next;
        }
    };
    ListItem
<T>* front(){
        
return _front;
    }
private:
    ListItem
<T>* _end;
    ListItem
<T>* _front;
    
long _size;
};

template
<typename T>
struct stl_iterator_traits{
    typedef typename T::value_type value_type;
};

template
<typename T>
struct stl_iterator_traits<T*>{
    typedef T value_type;
};

template
<typename T>
class AIter{
public:
    AIter(T
* p=0):ptr(p){};
    T
* ptr;
    typedef T value_type;
    T
& operator*()const{
        
return *ptr;
    }
    T
* operator->()const{
        
return ptr;
    }
};
template
<typename T>
typename stl_iterator_traits
<T>::value_type
func(T val){
    
return *val;
}
int _tmain(int argc, _TCHAR* argv[])
{
    List
<int> list;
    
for(int i=0;i<5;i++){
        list.insert_front(i);
        list.insert_end(i
+2);
    }
    list.display();
    
    
    List
<int>::iterator begin(list.front());
    List
<int>::iterator end;
    List
<int>::iterator iter;

    
//vector<int>::iterator itere;
    AIter<int> it(new int(2));
    
    iter
=find(begin,end,2);
    cout
<<iter->value()<<endl;
    
//list.insert_end(1);
    
//list.insert_end(2);
    
//list.display();
    
//list.insert_end(
    return 0;
}

现在对于class type q代器AIter,q是原生指针int* 或const int*,都能获取正确cdint
stl规定Q每个P代器都要自己内嵌型别定义的方式定义出相应型别
(待箋...)


]]>
Effective C++q蝲(?http://www.shnenglu.com/guojingjia2006/archive/2010/10/08/129008.html果?/dc:creator>果?/author>Fri, 08 Oct 2010 01:19:00 GMThttp://www.shnenglu.com/guojingjia2006/archive/2010/10/08/129008.htmlhttp://www.shnenglu.com/guojingjia2006/comments/129008.htmlhttp://www.shnenglu.com/guojingjia2006/archive/2010/10/08/129008.html#Feedback0http://www.shnenglu.com/guojingjia2006/comments/commentRss/129008.htmlhttp://www.shnenglu.com/guojingjia2006/services/trackbacks/129008.html阅读全文

]]>
޾Ʒþǧն| 99þþƷۺһ| þþƷ鶹ҹҹ| ľþþþר| 鶹Ʒþþһ| ˾þô߽ۺ5g| avԾþþþa| ھƷþþþӰԺվ| AVպƷþþþþ | ŷþþþƷӰԺ| þ99ֻƵƷ8| պݺݾþ͵͵ɫۺ| Aݺݾþɫ| ݺɫþۺ_| 9999Ʒŷþþþþ| þþù׮| þһٸ| þþƷþ| ޾ƷþþþĻ69 | ޹ۺϾþ | ޹һ˾þþƷ| þۺϾþԾ99ëƬ| պþӰԺ| þùƷ99þþþþ | ҹҹݺݾþAV| ҹþþþС˵| þþƷ| þþþþþ99Ʒѹۿ| ٸþ| þۺϾƷþ| þþþþþòҰ¸߳ | þþ㽶ۺϼձ| ɫɫۺϾþҹҹ| 2020˾þþƷ| Ļ޹˾þþƷ| þݺҹҹ| þþƷŷպþ| þþþþùƷ| þۺav| þ޾Ʒ벥| þݺҹҹavapp |