﻿<?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>BlogJava-weidagang2046的专栏-文章分类-C/C++</title><link>http://www.blogjava.net/weidagang2046/category/1276.html</link><description>物格而后知致</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 08:47:16 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 08:47:16 GMT</pubDate><ttl>60</ttl><item><title>C语言中对文件的随机存取</title><link>http://www.blogjava.net/weidagang2046/articles/91918.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Fri, 05 Jan 2007 02:49:00 GMT</pubDate><guid>http://www.blogjava.net/weidagang2046/articles/91918.html</guid><wfw:comment>http://www.blogjava.net/weidagang2046/comments/91918.html</wfw:comment><comments>http://www.blogjava.net/weidagang2046/articles/91918.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/weidagang2046/comments/commentRss/91918.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/weidagang2046/services/trackbacks/91918.html</trackback:ping><description><![CDATA[C语言中对文件的随机存取<br />C语言中要实现对文件的随机存 取，需要用到两个函数fseek()、ftell()。下面通过 一个反转显示指定文件的程序来介绍这两个函数的用法。<br />r eserve.c：<br /><br /><br /><br /><br /><br />#include &lt;<br />stdio.h&gt;<br />#include &lt;<br />stdlib.h&gt;<br /><br /><br />#define CNTL_Z '\032' / /DOS 文本中的文件结尾标记 <br />#define SL EN 50<br /><br />int main(int arg c, char *argv[])<br />{<br />c har file[SLEN];<br /><br />char ch ;<br /><br />FILE *fp;<br /><br />long count, last;<br /><br /><br />p uts("Enter the name of the fil e to be processed: ");<br /><br />gets(file);<br /><br />if( (fp = f open(file, "rb")) == NULL ) //只读和二进制模式 <br />{<br />printf("reverse can't open %s\n", file);<br /><br />exit( 1);<br /><br />} <br /><br />f seek(fp, 0L, SEEK_SET);<br />//定位在文件开头处 <br />la st = ftell(fp);<br /><br />printf( "fseek(fp, 0L, SEEK_SET) , fte el(p): %d\n", last);<br /><br />fseek(fp, 0L, SEEK_END);<br />//定位在文件结尾处 <br />last = ftell(fp);<br /><br />printf("fseek(fp, 0L, SEEK_END ) , fteel(p): %d\n", last);<br /><br /><br />for(count = 1L;<br />c ount &lt;<br />= last;<br />count++)<br />{<br />fseek(fp, -cou nt, SEEK_END);<br /><br />ch = getc(fp);<br /><br /><br />if(ch != CNTL_Z &amp;<br />&amp;<br />ch != '\r')<br />{<br />putchar(ch);<br /><br />}<br />}<br />putchar ('\n');<br /><br />fclose(fp);<br /><br /><br />system("PAUSE");<br /><br />return 0;<br /><br />}<br /><br />假定一个文 件test.txt内容为：<br /><br /><br /><br /><br /><br />1234567890<br />12345678 90<br />1234567890<br />1111111112 <br />2222222223<br />3333333334 <br />执行reserve来进行反转显示：<br />&lt; br&gt;<br /><br /><br /><br />Enter the n ame of the file to be processe d:<br />test.txt<br />fseek(fp, 0L , SEEK_SET) , fteel(p): 0<br />f seek(fp, 0L, SEEK_END) , fteel (p): 72<br /><br />4333333333<br />3222222222<br />2111111111<br />09 87654321<br />0987654321<br />0987 654321<br /><br />下面，我们来解释一下fseek ()和ftell()是如何工作的。<br />l fseek()函数<br /><br /><br /><br /><br />fseek（移动文件流的读写位置）<br /><br /><br />相 关函数 <br /><br />rewind，ftell，fgetp os，fsetpos，lseek<br /><br /><br />表头 文件 <br /><br />#include&lt;<br />stdio.h &gt;<br /><br /><br /><br />定义函数 <br /><br />i nt fseek(FILE * stream,long of fset,int whence);<br /><br /><br /><br />函 数说明 <br /><br />fseek()用来移动文件流的读写位 置。参数stream为已打开的文件指针，参数offset为根 据参数whence来移动读写位置的位移数。<br /><br />&lt; br&gt;参数 <br /><br />whence为下列其中一种:SE EK_SET从距文件开头offset位移量为新的读写位置。S EEK_CUR 以目前的读写位置往后增加offset个位移量 。SEEK_END将读写位置指向文件尾后再增加offset个 位移量。当whence值为SEEK_CUR 或SEEK_EN D时，参数offset允许负值的出现。下列是较特别的使用方式 :1) 欲将读写位置移动到文件开头时:fseek(FILE *stream,0,SEEK_SET);<br />2) 欲将读写位置移 动到文件尾时:fseek(FILE *stream,0,0S EEK_END);<br /><br /><br /><br />返回值 <br />&lt; br&gt;当调用成功时则返回0，若有错误则返回-1，errno会 存放错误代码。<br /><br /><br />附加说明 <br />fseek()不像lseek()会返回读写位置，因此必须 使用ftell()来取得目前读写的位置。<br /><br />l ftell()函数<br /><br /><br /><br /><br />ftell（取得文件流的读取位置）<br />&lt; br&gt;<br />相关函数 <br /><br />fseek，rewi nd，fgetpos，fsetpos<br /><br /><br />表头文件 <br /><br />#include&lt;<br />stdio .h&gt;<br /><br /><br /><br />定义函数 <br /><br />long ftell(FILE * stream);<br /><br /><br /><br />函数说明 <br /><br />ftell()用 来取得文件流目前的读写位置。参数stream为已打开的文件指 针。<br /><br /><br />返回值 <br /><br />当调用成 功时则返回目前的读写位置，若有错误则返回-1，errno会存 放错误代码。<br /><br /><br />错误代码 <br /><br />EBADF 参数stream无效或可移动读写位置的文件流。 <br /><br /><br />范例 <br /><br />参考fseek ()。<br /><br />通过fseek()、ftell()两 个函数，我们就可以随意访问文件的任何位置了，想了想好像操作文 件就这么easy，实在也没有更多可说的了。对了，fseek( )和ftell()存在一个潜在的问题就是他们限制文件的大小只 能在long类型的表示范围以内，也就是说通过这种方式，只能打 开2,000,000,000字节的文件，不过在绝大多数情况下 似乎也已经够用了。如果需要打开更大的文件，你需要用到fget pos()、fsetpos()函数了，那是另一个命题了。<br /><br />from: <a href="http://www.aonet.cn/artical/26/2005045581.htm">http://www.aonet.cn/artical/26/2005045581.htm</a><img src ="http://www.blogjava.net/weidagang2046/aggbug/91918.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/weidagang2046/" target="_blank">weidagang2046</a> 2007-01-05 10:49 <a href="http://www.blogjava.net/weidagang2046/articles/91918.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C语言学习进程:fseek与ftell函数</title><link>http://www.blogjava.net/weidagang2046/articles/91915.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Fri, 05 Jan 2007 02:46:00 GMT</pubDate><guid>http://www.blogjava.net/weidagang2046/articles/91915.html</guid><wfw:comment>http://www.blogjava.net/weidagang2046/comments/91915.html</wfw:comment><comments>http://www.blogjava.net/weidagang2046/articles/91915.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/weidagang2046/comments/commentRss/91915.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/weidagang2046/services/trackbacks/91915.html</trackback:ping><description><![CDATA[
		<blockquote class="bbquote">fseek函数是 用来设定文件的当前读写位置.<br /><br />函数原型: int fseek(FILE *fp,long offset,int origin);<br /><br />函数功能:把fp的文件读写位置指针移到指定的位置.<br /><br />fseek(fp,20,SEEK_SET); 意思是把fp文件读写位置指针从文件开始后移20个字节.<br /><br /><br /><br />ftell函数是用来获取文件的当前读写位置;<br /><br />函数原型: long ftell(FILE *fp)<br /><br />函数功能:得到流式文件的当前读写位置,其返回值是当前读写位置偏离文件头部的字节数.<br /><br />ban=ftell(fp); 是获取fp指定的文件的当前读写位置,并将其值传给变量ban.<br /><br /><br /><br />fseek函数与ftell函数综合应用:<br /><br />分析:可以用fseek函数把位置指针移到文件尾,再用ftell函数获得这时位置指针距文件头的字节数,这个字节数就是文件的长度.<br /><br /><pre>#include &lt;stdio.h&gt;

main()

{

   FILE *fp;

   char filename[80];

   long length;

   printf("输入文件名:");

   gets(filename);

   //以二进制读文件方式打开文件

   fp=fopen(filename,"rb");

   if(fp==NULL)

      printf("file not found!\n");

   else

      {

         //把文件的位置指针移到文件尾

          fseek(fp,OL,SEEK_END);

         //获取文件长度;

          length=ftell(fp);

          printf("该文件的长度为%1d字节\n",length);

          fclose(fp);

      }

}<br /><br /><br />from: <a href="http://my.opera.com/lau_jia/blog/show.dml/380421">http://my.opera.com/lau_jia/blog/show.dml/380421</a></pre></blockquote>
<img src ="http://www.blogjava.net/weidagang2046/aggbug/91915.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/weidagang2046/" target="_blank">weidagang2046</a> 2007-01-05 10:46 <a href="http://www.blogjava.net/weidagang2046/articles/91915.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++标准I/O重定向</title><link>http://www.blogjava.net/weidagang2046/articles/82106.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Sun, 19 Nov 2006 13:38:00 GMT</pubDate><guid>http://www.blogjava.net/weidagang2046/articles/82106.html</guid><wfw:comment>http://www.blogjava.net/weidagang2046/comments/82106.html</wfw:comment><comments>http://www.blogjava.net/weidagang2046/articles/82106.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/weidagang2046/comments/commentRss/82106.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/weidagang2046/services/trackbacks/82106.html</trackback:ping><description><![CDATA[#include &lt;iostream&gt;<br />#include &lt;fstream&gt;<br />int main()<br />{<br />    std::ofstream logFile("out.txt");<br />    std::streambuf *outbuf = std::cout.rdbuf(logFile.rdbuf());<br />    std::streambuf *errbuf = std::cerr.rdbuf(logFile.rdbuf());<br /><br />    // do the actual work of the program;<br />    // GUI code and event loop would go here<br />    std::cout &lt;&lt; "This would normally go to cout but goes to the log file\n";<br />    std::cerr &lt;&lt; "This would normally go to cerr but goes to the log file \n";<br />    logFile &lt;&lt; "This goes to the log file\n";<br />    // end of program body<br /><br />    // restore the buffers<br />    std::cout.rdbuf(outbuf);<br />    std::cerr.rdbuf(errbuf);<br />}<br /><br />rdbuf函数返回一个由基类basic_ios管理的流缓冲区的指针。重载版本允许你替换流缓冲区，返回值是原始的流缓冲区。解决方法很简单—用你的log文件的流缓冲区替换cout和cerr的流缓冲区。程序结束时，改回原来的流缓冲区。<img src ="http://www.blogjava.net/weidagang2046/aggbug/82106.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/weidagang2046/" target="_blank">weidagang2046</a> 2006-11-19 21:38 <a href="http://www.blogjava.net/weidagang2046/articles/82106.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC++2005快速构建安全的应用程序</title><link>http://www.blogjava.net/weidagang2046/articles/80282.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Thu, 09 Nov 2006 15:24:00 GMT</pubDate><guid>http://www.blogjava.net/weidagang2046/articles/80282.html</guid><wfw:comment>http://www.blogjava.net/weidagang2046/comments/80282.html</wfw:comment><comments>http://www.blogjava.net/weidagang2046/articles/80282.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/weidagang2046/comments/commentRss/80282.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/weidagang2046/services/trackbacks/80282.html</trackback:ping><description><![CDATA[　　<b>一、 简介</b><br /><br />　　微软的Visual C++2005发布版本对于有志于轻松、迅速地编写安全可靠的应用程序的编程爱好者来说是正确地选择。正如你所听到的那样，Visual C++中语言和库的新特点使开发安全、可靠的应用程序比以前更容易。它即提供了功能强大并且灵活的标准C++，又提供了适于.NET框架下编程的最强大的开发语言。<br /><br />　　本文中，我主要探讨Visual C++2005发布版本中部分语言和库的新特色，无论是对于教学项目还是大的应用工程，这都将帮助你在编写安全可靠的代码时提高工作效率。<br /><br />　　<b>二、C运行时库的安全特点</b><br /><br />　　如果你正在使用Visual C++创建使用C运行时库的应用程序，你将非常欣慰地了解到现在你所依赖的许多库函数都有了更安全的版本。对于需要一个或多个缓冲作为输入的函数来说，已经添加了长度参数，以此让函数来确信不会超越缓冲的边界。现在更多的函数开始对参数进行合法性检查，必要时将调用无效参数处理器。让我们来看一些简单的例子：<br /><br />　　C运行时库中最不可靠的是gets函数，它从标准输入中读取一行。思考下面的一个简单的例子：<br /><br /><table class="txcode" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>char buffer[10] = { 0 }; <br />gets(buffer);</td></tr></tbody></table><br />　　第一行代码声明了一个缓冲变量，并将缓冲区中的字符初始化设置为0。为避免意外情况发生将变量初始化为一个众所周知的值是一个非常好的主意。紧接着，看似清白无辜的gets函数从标准的输入流中读取一行并且写入到buffer缓冲区内。这有什么错误吗？对于函数来说C类型的数组不能实现值传递，而是传递了指向数组第一个元素的指针。所以在函数看来，char[ ]相当于char*指针，并且是一个不附带可以决定所指向的缓冲区大小尺寸的任何额外信息的原始指针。那么gets函数是怎么作的呢？它假设缓冲区无限大（UINT_MAX 是有精确尺寸的），并将持续地从输入流中拷贝字符到缓冲区内。攻击者可以轻易地使用这个弱点，这种不广为人知的类型错误被称为缓冲溢出。<br /><br />　　很多最初的C运行时库函数遭受同样的与参数确认有关的问题，并且现在因此受到抨击。一定要牢记对于当前所要写的应用程序来说，性能处于次要地位，我们现在生活在一个安全第一的世界。每一个受到批评的函数已经被一个提供同样函数功能，但添加了安全特点的函数所代替。当然，根据你在已经存在的代码中所使用的旧的库函数的多少，你可能需要花费一些时间来代码更替到新的、更安全的版本。这些新的函数有一个_s后缀，例如，gets函数被gets_s函数代替；遭受抨击的strcpy函数被strcpy_s函数代替。这里有一个例子：<br /><br /><table class="txcode" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>char buffer[10] = { 0 };<br />gets_s(buffer, sizeof (buffer) / sizeof (buffer[0]));</td></tr></tbody></table><br />　　gets_s函数有一个额外的参数，用来显示可以写入的最大字符数量，这里包括一个NULL终结符。我使用了sizeof操作符，它能决定数组的长度，因为编译器在编译时决定sizeof操作符返回的结果。记住，sizeof返回操作数的长度是以字节为单位的，所以用数组长度来除以数组中第一个元素的长度将返回数组中元素的个数。这种简单的方法可以移植到Unicode编码下使用_getws_s的情况，这个函数也需要得知以字节为单位的缓冲区长度。<br /><br />　　正如我所提到的，另外一个接受安全检查的常用函数strcpy函数，就象gets函数一样，它没有方法来保证有效的缓冲区尺寸，所以它只能假定缓冲足够大来容纳要拷贝的字符串。在程序运行时，这将导致不可预料的行为，正如我所提到的，为了安全需要避免这些不可预料的行为，这有一个使用安全的strcpy_s函数的例子。<br /><br /><table class="txcode" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>char source[] = Hello world!; <br />char destination[20] = { 0 }; <br />strcpy_s(destination, sizeof (destination) / sizeof (destination[0]), source);</td></tr></tbody></table><br />　　有很多原因来喜欢这个新的strcpy_s函数。最明显的区别是的额外的、以字节为单位的参数，它用来确认缓冲区大小。这允许strcpy_s函数可以进行运行时检查，以确定写入的字符没有超过目标缓冲区的边界。还有一些其它的检查方法来确定参数的有效性。在调试版本中这些检测方法，包括显示调试报告的断言（assertions）方法，如果它们的条件没有满足，它们将显示调试报告。无论是调试还是发行版本，如果一个特定的条件没有得到满足，一个无效的参数管理器将被调用，它默认的行为是抛出一个访问冲突来终止应用程序。这非常好的实现了让你的应用程序持续运行，而不会产生不可预期的结果。当然，这种情况完全可以通过确保类似于strcpy_s的函数不调用无效参数来避免。<br /><br />　　前一个例子可以通过新的_countof宏来进一步简化，这个宏移抛开了对有错误倾向的sizeof操作符的需要。_countof宏返回C类型数组的元素数量。这个宏本身对应了一个模版，如果传递一个原始指针的话，它将无法通过编译。这有一个例子：<br /><br /><table class="txcode" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>strcpy_s(destination, _countof(destination), source);</td></tr></tbody></table><br /><br /><br /><b>三、使用C++标准库</b><br /><br />　　已经看了C运行时库新增强的安全特性，让我们来看一下如何使用C++标准库来进一步减少你的代码中的相似错误。<br /><br />　　当你从C运行时库转向C++的标准库，让你从C++开始受益的一个最有效的方法是使用库中的矢量类（Vector class）。矢量类是C++标准库中的一个模仿一维T数组的容器类，这里T可以是事实上的任何类型，你的代码中使用缓冲区的地方都可以用矢量对象来代替。让我们来考虑上一节的例子，第一个例子我们使用gets_s函数来从标准输入中读取一个行，考虑用下面的代码代替：<br /><br /><table class="txcode" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>std::vector&lt;char&gt; buffer(10); <br />gets_s(&amp;buffer[0], buffer.size());</td></tr></tbody></table><br />　　最值得注意的一个区别是缓冲区变量现在是一个带有可用方法和操作符的矢量对象，这个矢量对象初始化为10个字节长度，并且构造函数将每个元素都初始化为0，表达式&amp;buffer[0]用于得到矢量对象的第一个元素的地址，向期待一个简单缓冲区的C函数传递一个矢量对象是一种正确的方法。与sizeof操作符不同的是，所有的容器的尺寸测量是基于元素的，而不是基与字节的。例如，矢量的size方法返回的是容器的元素数量。<br /><br />　　在上节的第二个例子里，我们使用strcpy_s函数从源缓冲区向目标缓冲区拷贝字符。应该清楚矢量对象是如何代替原始的C类型的数组，为了更好的说明这一点，让我们来考虑另外一个非常有用的C++标准库的容器。<br /><br />　　提供的basic_string类使得字符串在C++中可以作为正常的类型来操作。它提供了各种各样的重载操作符，为C++程序开发人员提供了自然的编程模式。由于优于strcopy_s及其它操作字符串的函数，你应该首选basic_string函数。basic_string以字节为单位的T类型容器。这里T是字符类型。C++标准类库对于常用的字符类型提供类型定义。string和wstring中的元素类型分别被定义为char和wchar类型。下面的例子说明basic_string类是多么简单和安全：<br /><br /><table class="txcode" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>std::string source = Hello world!; <br />std::string destination = source;</td></tr></tbody></table><br />　　basic_string类也提供了你所希望的、常用的字符串操作的方法和操作符，象字符串联合及子串的搜索。<br /><br />　　最后，C++标准库提供了一个功能非常强大的I/O库，用来安全、简单地与标准输入输出、文件流进行交互操作。虽然对于gets_s函数来说使用矢量对象比使用C类型的数组更好，但你可以通过使用定义的basic_istream 和 basic_ostream类进一步简化。实际上，你可以书写简单并且类型安全的代码从流中来读取包括字符串在内的任何类型。<br /><br /><table class="txcode" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>std::string word;<br />int number = 0; <br />std::cin &gt;&gt; word &gt;&gt; number; <br />std::cout &lt;&lt; word<br />&lt;&lt; std::endl <br />&lt;&lt; number <br />&lt;&lt; std::endl;</td></tr></tbody></table><br />　　cin被定义成一个basic_istream流，从标准的输入中提取字符类型的元素。wcin是用于wchar_t元素。另一方面，cout被定义为一个basic_ostream流，用于向标准的输出流写入操作。正如你能想象的，这种模式比起gets_s和puts函数来可以无限的扩展。但是，真正的价值是在于它非常难以产生让你的应用程序出现安全裂痕的错误。<br /><br />　　<b>四、C++标准库中的边界检查</b><br /><br />　　默认情况，C++标准库中大量的容器对象和迭代对象没有提供边界检查。例如，矢量的下标操作符通常是一个比较快，但有潜在的危险性的操作单独元素的方法。如果你正在寻找得到确认检查的操作方法，你可以转向at方法。安全性的增加是以牺牲性能为代价的。当然，绝大情况下性能的降低是可以忽略不计的，但是对于性能要求第一位的代码来说，这可能是非常有害的，思考一下下面的简单函数：<br /><br /><table class="txcode" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>void PrintAll(const std::vector&lt;int&gt;&amp; numbers) <br />{ <br />　for (size_t index = 0; index &lt; numbers.size(); ++index)<br />　{<br />　　std::cout &lt;&lt; numbers[index] &lt;&lt; std::endl;<br />　} <br />} <br />void PrintN(const std::vector&lt;int&gt;&amp; numbers, size_t index) <br />{ <br />　std::cout &lt;&lt; numbers.at(index) &lt;&lt; std::endl; <br />}</td></tr></tbody></table><br />　　PrintAll函数使用了下标操作符，因为索引由函数控制，并且可以确认是安全的。另一方面，PrintN函数不能保证索引的有效性，所以它使用了更安全的at方法来代替。当然，并不是所有的容器的存取操作都象这么简洁明了。<br /><br />　　在保证C++标准库的安全特性的同时，Visual C++2005继续坚持并在很多情况下改进了C++标准库的运行特性，同时提供了调节C++标准库安全性的特色。一项受人欢迎的改进是在调试版本中添加了范围检查，这对你的发行版本性能并不构成影响。但这确实帮助你在调试阶段捕获越界错误，甚至是使用传统上不安全的下标操作符的代码。<br /><br />　　不安全的函数，象vector的下标操作算子，和其他的函数，象它的front函数，如果不恰当的调用，通常会导致不明确的行为。如果你幸运的话，它将很快导致一个存取冲突，这将使你的应用程序崩溃。如果你不那么走运的话，它可能默默地持续运转并导致不可预知的副效应，这将破坏数据并可能被进攻者利用。为了保护你的发行版本的应用程序，Visual C++2005引入了_SECURE_SCL符号，用来给那些非安全的函数添加运行时检查。象下面的代码那样在你的应用程序中简单地定义这个符号可以添加额外的实时检查并阻止不确切的行为。<br /><br /><table class="txcode" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>#define _SECURE_SCL 1</td></tr></tbody></table><br />　　紧记定义这个符号对你的程序冲击很大，大量的合法的，但是具有潜在非安全的操作将在编译时将无法通过，以避免在运行时出现潜在BUG。思考下面的使用Copy运算的例子：<br /><br /><table class="txcode" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>std::copy(first, last, destination);</td></tr></tbody></table><br />　　其中，first和last是定义拷贝范围的迭代参数，destination是输出迭代参数，指示了目标缓冲区的位置，这个位置用来拷贝范围之内的第一个元素。这里有一个危险是destination所对应的目标缓冲区或容器不足够大，无法容纳所要拷贝的元素。如果Destination是一个需要安全检查的迭代参数，类似的错误将被捕获。但是，这仅仅是一个假设。如果destination是一个简单的指针，将无法保证copy运算函数正确运转。这时当然会想到_SECURE_SCL符号来避免这一问题，这种情况下，代码甚至是不能编译，以此避免任何可能的运行时错误。就象你想象的那样，这将需要重写更完美有效的代码。所以，这是一个更好的理由支持C++标准库容器，避免使用C类型数组。<br /><br /><br /><b>五、编译器的安全特点</b><br /><br />　　虽然对于Visual C++2005来说并不是全新的，但大量编译器特色仍然需要了解。与以前版本的显著区别是编译器的安全检查当前默认情况下是打开的，让我们来看一下编译器的特点及在某些情况下它们是如何阻止在某些情况下受到攻击。<br /><br />　　Visual C++编译器很久以前就开始提供严格的运行时安全检查选项，包括栈校验，下溢和上溢检查以及未初始化变量的识别。这些运行时检查由编译器的/RTC选项来控制。虽然在早期的发展中捕获错误非常有用，但是对于发布版本性能上的损失却是不能接受的。微软的Visual C++.NET引入了/GS编译开关，对于发行版本来说它添加了有限的运行时安全检查。/GS开关在编译开关中插入代码，通过检测函数的栈数据来检测通常基于栈的缓冲溢出。如果发现问题，应用程序将被终止。为了减少运行时检查对性能的影响，编译器辨别哪个函数易于攻击并且仅针对这些函数来进行安全检查。安全检查涉及到在函数的栈框架上增加一个cookie，在缓冲溢出的情况下它将被重写。函数指令的前后都添加了汇编指令。在函数执行以前，源自cookie模块的函数cookie先执行计算。当函数结束但在栈空间被收回前，cookie的栈拷贝被检索以判断它是否被更改。如果cookie未被更改，函数结束并继续执行程序的下一步，如果cookie被更改了，一个安全错误句柄将被调用，它将结束应用程序。<br />为了在Visual C++ 2005发布版本中控制这些编译选项，打开工程的属性页，单击C/C++标签，在代码发生属性页中，你将发现两个属性对应于我刚刚描述的特点。Basic Runtime Checks属性对应于开发时/RTC编译选项，在编译版本中应设置为BOTH。Buffer Security Check属性相当于编译器的/GS选项，对于发布版本应设置为YES。<br /><br />　　对于使用Visual C++ 2005的开发人员来说，这些编译特点在默认情况下打开，这意味着你可以确信编译器正在尽其可能阻止你代码中的漏洞。然而，这并不意味着我们可以完全不关心安全问题。开发人员需要继续为正确的代码而努力，并且要考虑各种不同的、可能发生的安全威胁。编译器仅仅可以阻止部分类型的错误发生。<br /><br />　　要牢记这些编译器提供的特殊的安全检查仅适用于本地代码，幸运的是，托管代码很少犯此类的错误。这里甚至于有更好的消息，Visual C++ 2005引进了C++/CLI设计语言，它提供了.NET框架下最强有力的开发语言。<br /><br />　　<b>六、新的C++编程语言</b><br /><br />　　Visual C++ 2005发布版本提供了C++/CLI设计语言的一流的实现。C++/CLI是为.NET设计的系统编程语言。相对于其他语言来说，它在创建和使用.NET模块和汇编上有更多的控制。C++/CLI对于C++开发人员来说更精细和自然，无论你是否熟悉C++或.NET框架，你将发现使用C++书写托管代码是对ANSI C++自然文雅的扩展，学习起来非常容易。<br /><br />　　对于开发应用程序来说，有许多强制性的原因让你来选择托管代码而不是本地C++。两个最重要的原因是安全性和效率。通用运行时语言（CLR）给你的代码提供了一个安全的运行环境。作为一个程序开发人员，你不需要关心缓冲区溢出及因为你在使用前未初始化变量等问题。安全问题没有完全消失，但是使用托管可以避免通常发生的一些错误。<br /><br />　　另外一个使用托管的原因是.NET框架下丰富的类库。虽然标准C++库更适合于C++类型编程，但是.NET框架包含了一个功能强大的函数库，这是标准C++库所无法比拟的。.NET框架包括很多有用的集合类、一个强大的数据操作库、执行很多流行的通讯协议的类，从SOCKETS到HTTP和网络服务等等。虽然本地C++程序开发人员可以以各种形似使用这些服务，但通过使用.NET框架获取的生产力主要因为它的统一性和连贯性。无论你是用System::Net::Sockets还是用System::Web名字空间，你将面对同样的类型，描述广泛应用的概念，例如流和字符串。这是.NET框架具有开发高效率的最主要的原因。这让程序人员更快速地书写更强有力的应用程序，同时代码更可靠。<br /><br />　　Visual C++ 2005自然地准许你在一个工程中混合本地与托管代码，你可以继续使用已经存在的本地函数及类的同时，开始使用越来越多的.NET框架下的类库，甚至是写你的托管类型。你可以将你的托管类型定义为一个引用类型或一个值类型，虽然Visual C++编译器允许你为了方面选择使用栈语法或是为了控制管理资源使用通常的作用域规则，但值类型在栈上而引用类型位于CLR的托管堆上。 <br /><br />　　通过在你定义的class 和 struct 前添加ref来形成一个关键词，定义了一个引用类型。获取和释放资源按通常的方式完成，通过使用构造和析构函数，正如这里说明的：<br /><br /><table class="txcode" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>ref class Connection<br />{ <br />　public: Connection(String^ server) <br />　{<br />　　Server = server; <br />　　Console::WriteLine(Aquiring connection to server.);<br />　}<br />　~Connection() <br />　{<br />　　Console::WriteLine(Disconnecting from server.); <br />　}<br />　property String^ Server; <br />};</td></tr></tbody></table><br />　　编译器负责Connection引用类型的IDisposable接口的实现，所以使用类似C#、Visual Basic.NET的开发人员可以使用任何对他们可用的资源管理结构。对于C++开发人员，有着与以前一样的选择。为了简化资源管理，并书写异常安全代码，你可以简单地在栈上声明一个Connection对象。当一个对象超过其作用范围后，执行Dispose方法的析构函数将被调用。下面是一个例子：<br /><br /><table class="txcode" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>void UseStackConnection()<br />{<br />　Connection connection(sample.kennyandkarin.com); <br />　Console::WriteLine(Connection to {0} established!, <br />　connection.Server);<br />}</td></tr></tbody></table><br />　　这个例子中，通过在函数返回调用前调用析构函数来关闭这个Connection，这正如你在C++希望的那样。如果你希望自己控制对象的生命期，仅仅需要使用gcnew这个关键词来获取connection对象的句柄。这个指针可以看作通常的指针（不含有通常的缺陷），并且这个对象的析构函数可以简单地通过delete操作来调用。这个例子代码如下 ：<br /><br /><table class="txcode" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>void UseHeapConnection()<br />{<br />　Connection^ connection = gcnew Connection(sample.kennyandkarin.com);<br />　try<br />　{<br />　　Console::WriteLine(Connection to {0} established!,<br />　　connection-&gt;Server);<br />　}<br />　finally<br />　{<br />　　delete connection;<br />　}<br />}</td></tr></tbody></table><br />　　正如你所看到的，从本地C++到托管代码，Visual C++ 2005带来了简单灵活的资源管理方式，可以书写强壮的资源管理代码对于书写正确、安全的代码是非常重要的。<br /><br />　　<b>七、小结</b><br /><br />　　无论是对于一个小的程序还是一个大的应用，Visual C++ 2005发布版本都是一个功能强大的开发工具，C运行时库和C++标准库提供了一个强大的工具集，来发布功能强大的、强壮的本地应用程序，同时，对用C++书写托管代码有着一流的支持，Visual C++ 2005在微软的Windows开发平台上是独一无二的强大的开发工具。<br /><br />from: <a href="http://www.97t.org/ArticleView/2005-9-4/Article_View_241.Htm">http://www.97t.org/ArticleView/2005-9-4/Article_View_241.Htm</a><img src ="http://www.blogjava.net/weidagang2046/aggbug/80282.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/weidagang2046/" target="_blank">weidagang2046</a> 2006-11-09 23:24 <a href="http://www.blogjava.net/weidagang2046/articles/80282.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用C++实现简单的文件I/O操作</title><link>http://www.blogjava.net/weidagang2046/articles/74898.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Fri, 13 Oct 2006 00:45:00 GMT</pubDate><guid>http://www.blogjava.net/weidagang2046/articles/74898.html</guid><wfw:comment>http://www.blogjava.net/weidagang2046/comments/74898.html</wfw:comment><comments>http://www.blogjava.net/weidagang2046/articles/74898.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/weidagang2046/comments/commentRss/74898.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/weidagang2046/services/trackbacks/74898.html</trackback:ping><description><![CDATA[   文件 I/O 在C++中比烤蛋糕简单多了。 在这篇文章里，我会详细解释ASCII和二进制文件的输入输出的每个细节，值得注意的是，所有这些都是用C++完成的。<br /><br />　　一、ASCII 输出<br /><br />　　为了使用下面的方法, 你必须包含头文件&lt;fstream.h&gt;(译者注：在标准C++中，已经使用&lt;fstream&gt;取代&lt; fstream.h&gt;，所有的C++标准头文件都是无后缀的。)。这是 &lt;iostream.h&gt;的一个扩展集, 提供有缓冲的文件输入输出操作. 事实上, &lt;iostream.h&gt; 已经被&lt;fstream.h&gt;包含了, 所以你不必包含所有这两个文件, 如果你想显式包含他们，那随便你。我们从文件操作类的设计开始, 我会讲解如何进行ASCII I/O操作。如果你猜是"fstream," 恭喜你答对了！ 但这篇文章介绍的方法,我们分别使用"ifstream"?和 "ofstream" 来作输入输出。<br /><br />　　如果你用过标准控制台流"cin"?和 "cout," 那现在的事情对你来说很简单。 我们现在开始讲输出部分，首先声明一个类对象。ofstream fout;<br /><br />　　这就可以了，不过你要打开一个文件的话, 必须像这样调用ofstream::open()。<br /><br />fout.open("output.txt");<br /><br />　　你也可以把文件名作为构造参数来打开一个文件.<br /><br />ofstream fout("output.txt");<br /><br />　　这是我们使用的方法, 因为这样创建和打开一个文件看起来更简单. 顺便说一句, 如果你要打开的文件不存在，它会为你创建一个, 所以不用担心文件创建的问题. 现在就输出到文件，看起来和"cout"的操作很像。 对不了解控制台输出"cout"的人, 这里有个例子。<br /><br />int num = 150;<br />char name[] = "John Doe";<br />fout &lt;&lt; "Here is a number: " &lt;&lt; num &lt;&lt; "\n";<br />fout &lt;&lt; "Now here is a string: " &lt;&lt; name &lt;&lt; "\n";<br /><br />　　现在保存文件，你必须关闭文件，或者回写文件缓冲. 文件关闭之后就不能再操作了, 所以只有在你不再操作这个文件的时候才调用它，它会自动保存文件。 回写缓冲区会在保持文件打开的情况下保存文件, 所以只要有必要就使用它。回写看起来像另一次输出, 然后调用方法关闭。像这样：<br /><br />fout &lt;&lt; flush; fout.close();<br /><br />　　 现在你用文本编辑器打开文件，内容看起来是这样：<br /><br />　　Here is a number: 150 Now here is a string: John Doe<br /><br />　　很简单吧! 现在继续文件输入, 需要一点技巧, 所以先确认你已经明白了流操作，对 "&lt;&lt;" 和"&gt;&gt;" 比较熟悉了, 因为你接下来还要用到他们。继续…<br /><br />　　二、ASCII 输入<br /><br />　　输入和"cin" 流很像. 和刚刚讨论的输出流很像, 但你要考虑几件事情。在我们开始复杂的内容之前, 先看一个文本：<br /><br />　　12 GameDev 15.45 L This is really awesome!<br /><br />　　为了打开这个文件，你必须创建一个in-stream对象,?像这样。<br /><br />ifstream fin("input.txt");<br /><br />　　现在读入前四行. 你还记得怎么用"&lt;&lt;" 操作符往流里插入变量和符号吧？好,?在 "&lt;&lt;" (插入)?操作符之后，是"&gt;&gt;" (提取) 操作符. 使用方法是一样的. 看这个代码片段.<br /><br />int number;<br />float real;<br />char letter, word[8];<br />fin &gt;&gt; number; fin &gt;&gt; word; fin &gt;&gt; real; fin &gt;&gt; letter;<br /><br />　　也可以把这四行读取文件的代码写为更简单的一行。<br /><br />fin &gt;&gt; number &gt;&gt; word &gt;&gt; real &gt;&gt; letter;<br /><br />　　它是如何运作的呢? 文件的每个空白之后, "&gt;&gt;" 操作符会停止读取内容, 直到遇到另一个&gt;&gt;操作符. 因为我们读取的每一行都被换行符分割开(是空白字符), "&gt;&gt;" 操作符只把这一行的内容读入变量。这就是这个代码也能正常工作的原因。但是，可别忘了文件的最后一行。<br /><br />　　This is really awesome!<br /><br />　　如果你想把整行读入一个char数组, 我们没办法用"&gt;&gt;"?操作符，因为每个单词之间的空格（空白字符）会中止文件的读取。为了验证：<br /><br />char sentence[101]; fin &gt;&gt; sentence;<br /><br />　　我们想包含整个句子, "This is really awesome!" 但是因为空白, 现在它只包含了"This". 很明显, 肯定有读取整行的方法, 它就是getline()。这就是我们要做的。<br /><br />fin.getline(sentence, 100);<br /><br />　　这是函数参数. 第一个参数显然是用来接受的char数组. 第二个参数是在遇到换行符之前，数组允许接受的最大元素数量. 现在我们得到了想要的结果：“This is really awesome!”。<br /><br />　　你应该已经知道如何读取和写入ASCII文件了。但我们还不能罢休，因为二进制文件还在等着我们。<br /><br />　　三、二进制 输入输出<br /><br />　　二进制文件会复杂一点, 但还是很简单的。首先你要注意我们不再使用插入和提取操作符(译者注：&lt;&lt; 和 &gt;&gt; 操作符). 你可以这么做，但它不会用二进制方式读写。你必须使用read() 和write() 方法读取和写入二进制文件. 创建一个二进制文件, 看下一行。<br /><br />ofstream fout("file.dat", ios::binary);<br /><br />　　这会以二进制方式打开文件, 而不是默认的ASCII模式。首先从写入文件开始。函数write() 有两个参数。 第一个是指向对象的char类型的指针, 第二个是对象的大小（译者注：字节数）。 为了说明，看例子。<br /><br />int number = 30; fout.write((char *)(&amp;number), sizeof(number));<br /><br />　　第一个参数写做"(char *)(&amp;number)". 这是把一个整型变量转为char *指针。如果你不理解，可以立刻翻阅C++的书籍，如果有必要的话。第二个参数写作"sizeof(number)". sizeof() 返回对象大小的字节数. 就是这样!<br /><br />　　二进制文件最好的地方是可以在一行把一个结构写入文件。 如果说，你的结构有12个不同的成员。 用ASCII?文件，你不得不每次一条的写入所有成员。 但二进制文件替你做好了。 看这个。<br /><br />struct OBJECT { int number; char letter; } obj;<br />obj.number = 15;<br />obj.letter = ‘M’;<br />fout.write((char *)(&amp;obj), sizeof(obj));<br /><br />　　这样就写入了整个结构! 接下来是输入. 输入也很简单，因为read()?函数的参数和 write()是完全一样的, 使用方法也相同。<br /><br />ifstream fin("file.dat", ios::binary); fin.read((char *)(&amp;obj), sizeof(obj));<br /><br />　　我不多解释用法, 因为它和write()是完全相同的。二进制文件比ASCII文件简单, 但有个缺点是无法用文本编辑器编辑。 接着, 我解释一下ifstream 和ofstream 对象的其他一些方法作为结束.<br /><br />　　四、更多方法<br /><br />　　我已经解释了ASCII文件和二进制文件, 这里是一些没有提及的底层方法。<br /><br />　　检查文件<br /><br />　　你已经学会了open() 和close() 方法, 不过这里还有其它你可能用到的方法。<br /><br />　　方法good() 返回一个布尔值，表示文件打开是否正确。<br /><br />　　类似的，bad() 返回一个布尔值表示文件打开是否错误。 如果出错，就不要继续进一步的操作了。<br /><br />　　最后一个检查的方法是fail(), 和bad()有点相似, 但没那么严重。<br /><br />　　读文件<br /><br />　　方法get() 每次返回一个字符。<br /><br />　　方法ignore(int,char) 跳过一定数量的某个字符, 但你必须传给它两个参数。第一个是需要跳过的字符数。 第二个是一个字符, 当遇到的时候就会停止。 例子,<br /><br />fin.ignore(100, ‘\n’);<br /><br />　　会跳过100个字符，或者不足100的时候，跳过所有之前的字符，包括 ‘\n’。<br /><br />　　方法peek() 返回文件中的下一个字符, 但并不实际读取它。所以如果你用peek() 查看下一个字符, 用get() 在peek()之后读取，会得到同一个字符, 然后移动文件计数器。<br /><br />　　方法putback(char) 输入字符, 一次一个, 到流中。我没有见到过它的使用，但这个函数确实存在。<br /><br />　　写文件<br /><br />　　只有一个你可能会关注的方法.?那就是 put(char), 它每次向输出流中写入一个字符。<br /><br />　　打开文件<br /><br />　　当我们用这样的语法打开二进制文件:<br /><br />ofstream fout("file.dat", ios::binary);<br /><br />　　"ios::binary"是你提供的打开选项的额外标志. 默认的, 文件以ASCII方式打开, 不存在则创建, 存在就覆盖. 这里有些额外的标志用来改变选项。<br /><br />　　ios::app 添加到文件尾<br />　　ios::ate 把文件标志放在末尾而非起始。<br />　　ios::trunc 默认. 截断并覆写文件。<br />　　ios::nocreate 文件不存在也不创建。<br />　　ios::noreplace 文件存在则失败。<br /><br />　　文件状态<br /><br />　　我用过的唯一一个状态函数是eof(), 它返回是否标志已经到了文件末尾。 我主要用在循环中。 例如, 这个代码断统计小写‘e’ 在文件中出现的次数。<br /><br />ifstream fin("file.txt");<br />char ch; int counter;<br />while (!fin.eof()) {<br />ch = fin.get();<br />if (ch == ‘e’) counter++;<br />}<br />fin.close();<br /><br />　　我从未用过这里没有提到的其他方法。 还有很多方法，但是他们很少被使用。参考C++书籍或者文件流的帮助文档来了解其他的方法。<br /><br />　　结论<br /><br />　　你应该已经掌握了如何使用ASCII文件和二进制文件。有很多方法可以帮你实现输入输出，尽管很少有人使用他们。我知道很多人不熟悉文件I/O操作，我希望这篇文章对你有所帮助。 每个人都应该知道. 文件I/O还有很多显而易见的方法,?例如包含文件 &lt;stdio.h&gt;. 我更喜欢用流是因为他们更简单。 祝所有读了这篇文章的人好运, 也许以后我还会为你们写些东西。  <br /><br />from: <a href="http://www.cnsdn.com.cn/inc/show.asp?id=3462">http://www.cnsdn.com.cn/inc/show.asp?id=3462</a><img src ="http://www.blogjava.net/weidagang2046/aggbug/74898.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/weidagang2046/" target="_blank">weidagang2046</a> 2006-10-13 08:45 <a href="http://www.blogjava.net/weidagang2046/articles/74898.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++的多态性实现机制剖析</title><link>http://www.blogjava.net/weidagang2046/articles/74179.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Mon, 09 Oct 2006 14:02:00 GMT</pubDate><guid>http://www.blogjava.net/weidagang2046/articles/74179.html</guid><wfw:comment>http://www.blogjava.net/weidagang2046/comments/74179.html</wfw:comment><comments>http://www.blogjava.net/weidagang2046/articles/74179.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/weidagang2046/comments/commentRss/74179.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/weidagang2046/services/trackbacks/74179.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: C++																																的多态性实现机制剖析																																																																																																																										――即...&nbsp;&nbsp;<a href='http://www.blogjava.net/weidagang2046/articles/74179.html'>阅读全文</a><img src ="http://www.blogjava.net/weidagang2046/aggbug/74179.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/weidagang2046/" target="_blank">weidagang2046</a> 2006-10-09 22:02 <a href="http://www.blogjava.net/weidagang2046/articles/74179.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>学STL Iterator，traits笔记</title><link>http://www.blogjava.net/weidagang2046/articles/71698.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Mon, 25 Sep 2006 03:48:00 GMT</pubDate><guid>http://www.blogjava.net/weidagang2046/articles/71698.html</guid><wfw:comment>http://www.blogjava.net/weidagang2046/comments/71698.html</wfw:comment><comments>http://www.blogjava.net/weidagang2046/articles/71698.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/weidagang2046/comments/commentRss/71698.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/weidagang2046/services/trackbacks/71698.html</trackback:ping><description><![CDATA[
		<p>最近看侯杰老师的《STL源码剖析》有一点收获，特把我对STL iterator设计的认识草草记录下来，大部分内容来自那本书(看原书更好)。欢迎大家跟我讨论，里面也有问题希望您能提供宝贵看法！</p>
		<p>
				<strong>一. Iterator认识</strong>
				<br />如果需要构造一组通用容器，提供一套统一的算法，构造底层数据结构类库，iterator的设计无疑是非常重要的。iterator可以方便容器元素的遍历，提供算法的统一参数接口。怎么说？首先，让我们考虑一个算法。<br /><font color="#006400">Template &lt;class T&gt; ptrdiff_t<br />distance(T p1, T p2)<br />{<br />  //计算p1和p2之间的距离<br />}</font><br />显然这个函数是想计算两个“位置”之间距离。这里表示“位置”的类型T，可以是指向数组中某个元素的（原生）指针，可以是指向链表节点的指针，也可以是用来记录位置的任何对象（例如我们要谈的iterator）。不管这两个位置是对应在数组，vector，链表或是其他任何容器，我们当然希望设计好的类库中最好只要一个这样的distance函数，而不需要每种容器都有不同的“位置”记录方式，从而导致需要很多个这样的distance算法。对，我们完全可以抽象出一种表示“位置”的概念，它像游标，像智能的指针，可以方便的遍历容器中的元素，记录位置，而不用管你作用的是什么类型的容器，这就是现在被容器设计者普遍接受的iterator概念。<br /><br /><br /><br /><br /></p>
		<p>二. STL iterator的设计：<br /><strong>为什么不用继承构造iterator？</strong><br />容器抽象出5种iterator 类型，input&lt;--forward&lt;--bidrectional&lt;--random access iterator加上output iterator，我们能不能通过refinement关系设计出具有继承关系的几个iterator类？然后各个容器的iterator类去继承这些基类。那么上面的disatance函数可以设计两个版本<br /><font color="#006400">ptrdiff_t distance(InputIterator p1, InputIterator p2)<br />{<br /> //InputIterator只能一个一个前进,例如链表<br />  ptrdiff_t n=0;<br />  while(p1 != p2)<br />  {<br />   ++p1; ++n;   <br />  }<br />  return n;<br />} </font></p>
		<p>
				<font color="#006400">ptrdiff_t distance(RandomAccessIterator p1, RandomAccessIterator p2)<br />{<br /> //RandomAccessIterator可以直接计算差距，例如数组，vector等<br /> return p2-p1;<br />}</font>
		</p>
		<p>这样看来是可行的对吗？但为什么STL不采用这种方式呢？（各位帮我想想啊，我实在是菜，想不出很好的理由啊）我所能想到的有：iterator可以是原生指针的类型，而原生指针是不会继承InputIterator基类的。（是不是还有效率问题？)</p>
		<p>不讨论STL为什么不这么作，还是看看它漂亮的处理方法吧：先提醒你，它用的是函数模板（function template）的参数推导机制来确定函数返回值和参数类型的。</p>
		<p>
				<strong>(1)</strong>  通过不同的iterator概念，先作几个表明iterator类型的tag类。input_iterator_tag&lt;--forward_iterator_tag&lt;--bidrectonal_iterator_tag&lt;--random_access_iterator_tag。还有output_iterator_tag，这几个类都是空的，前面4个有继承关系。</p>
		<p>
				<strong>(2)</strong>  STL设计的iterator类都需要typedef一个重要的类型iterator_category用来表明这个iterator是什么类型的iterator，它必须是上面tag类中的一个。例如list&lt;T&gt;的iterator类有：<br />    typedef bidrectonal_iterator_tag iterator_category;<br />    <br />    另外需要有一个value_type类型表明iterator是指向什么类型的元素。例如list&lt;T&gt;的iterator类有：<br />    typedef T value_type;</p>
		<p>
				<strong>(3)</strong>  设计iterator_traits&lt;class Iterator&gt;类，这个类的作用是可以提取出模板参数Iterator类的类型。也是通过typedef实现的。如下：<br /><font color="#006400">template &lt;class Iterator&gt;<br />struct <strong>iterator_traits</strong> {<br />  typedef typename Iterator::iterator_category iterator_category;<br />  typedef typename Iterator::value_type        value_type;<br />  //.....<br />};</font></p>
		<p>本来第二步中，我们设计的iterator类已经可以通过typedef别名来标志类型了，为什么要这层中间转换？原因是通常我们可以写Iterator::iterator_category作为一个typename，<strong>但如果Iterator是一个原生指针T*，</strong>我们写T*::iterator_category就得不到啦。利用partial specialization（模板偏特化）技术，可以通过中间层iterator_traits自己指定并得到原生指针的iterator_category类型，代码如下。（这么复杂的编译技术，真不知他们咋整的...吾辈只能望洋兴叹55）</p>
		<p>
				<font color="#006400">template &lt;class T&gt;<br />struct iterator_traits&lt;T*&gt; {<br />  typedef random_access_iterator_tag iterator_category;<br />  typedef T                          value_type;<br />  //........<br />};</font>
		</p>
		<p>
				<strong>(4)</strong>  设想要设计一个算法template &lt;class Iterator&gt; RET_TYPE gen_fun(Iterator p1, Iterator p2, ...)。<br />一般这么处理：<br /><font color="#006400">template &lt;class Iterator&gt; RET_TYPE gen_fun(Iterator p1, Iterator p2, ...)<br />{<br />   <strong> typedef iterator_traits&lt;Iterator&gt;::iterator_category category;</strong>    <br />    typedef iterator_traits&lt;Iterator&gt;::value_type type;  //这个type用于实际运算中得知iterator指向的对象(*运算符返回类型)<br />   __gen_fun(Iterator p1, Iterator p2, ...,<strong> category()</strong>);<br />}</font></p>
		<p>category()构造一个iterator_tag类型的临时变量，该临时变量只用于区分调用函数，不参与实际算法实现。具体实现方法如下：(注意最后的参数不用变量名)</p>
		<p>
				<font color="#006400">template &lt;class Iterator&gt; RET_TYPE __gen_fun(Iterator p1, Iterator p2, ..., <strong>input_iterator_tag</strong>)<br />{<br />   //input_iterator类型的实际实现方法<br />   //并且由于tag类继承机制，forward_iterator类型也会调用本方法<br />}</font>
				<br /> <br /><font color="#006400">template &lt;class Iterator&gt; RET_TYPE __gen_fun(Iterator p1, Iterator p2, ..., <strong>bidrectonal_iterator_tag</strong>)<br />{<br />   //bidrectonal_iterator类型的实际实现方法<br />}</font></p>
		<p>
				<font color="#006400">template &lt;class Iterator&gt; RET_TYPE __gen_fun(Iterator p1, Iterator p2, ..., <strong>random_access_iterator_tag</strong>)<br />{<br />   //random_access_iterator类型的实际实现方法<br />}</font>
		</p>
		<p>这样通过定义iterator tag和函数模板的参数推导机制，就实现了参数类型识别，达到了构造继承关系的iterator类实现的功能。并且没有继承要求那么严格，而且typedef是在编译时候完成的工作，丝毫不影响程序运行速度。如果增加iterator中typedef的类型，如pointer等，可以增强参数类型识别的功能。</p>
		<p>另外需要提醒的是，在STL代码中，如果是random_access_iterator类型的方法，它通常写<br /><font color="#006400">template &lt;class <strong>RandomAccessIterator</strong>&gt; RET_TYPE __gen_fun(<strong>RandomAccessIterator</strong> p1, <strong>RandomAccessIterator</strong> p2, ..., random_access_iterator_tag)</font><br />是input_iterator类型的方法，它通常写<br />template &lt;class InputIterator&gt; RET_TYPE __gen_fun(InputIterator p1, InputIterator p2, ..., input_iterator_tag)<br />但是，<strong>别被这里的RandomAccessIterator和InputIterator迷惑了</strong>，它们只是模板参数而已，并没有继承关系，也不存在这样的类！（我就被这个迷惑了好久:( ）也不是我开头提的构造一组继承关系的Iterator类。模板参数写成RandomAccessIterator并不能表示该RandomAccessIterator类型就是random_access_iterator的，它写成T，Type，Iter都没有关系。只有通过iterator_traits得到iterator_tag才能表明iterator的真正类型。我想它那样写，只是为了提醒你调用函数的iterator类型吧。<br /></p>
		<p>
				<br />
				<br />
				<strong>三. 最后看看开头提的distance()算法实际实现</strong>：</p>
		<p>
				<font color="#006400">template &lt;class Iterator&gt; inline <br /> typename iterator_traits&lt;Iterator&gt;::iterator_category<br />  iterator_category(const Iterator&amp;)  <br />  //提取Iterator的iterator_category类型<br />{<br />  typedef typename iterator_traits&lt;Iterator&gt;::iterator_category category;<br />  return category();<br />}</font>
		</p>
		<p>
				<br />
				<font color="#006400">template &lt;class InputIterator, class Distance&gt;<br />inline void distance(InputIterator first, InputIterator last, Distance&amp; n)  <br />{<br />  __distance(first, last, n, <strong>iterator_category(first)</strong>);<br />  //根据提取的iterator_category类型选择实际执行函数<br />  //Distance是通过引用传递，相当于函数返回值<br />}</font>
		</p>
		<p>
				<br />
				<font color="#006400">template &lt;class InputIterator, class Distance&gt;<br />inline void __distance(InputIterator first, InputIterator last, Distance&amp; n, <br />                       <strong>input_iterator_tag</strong>) <br />{<br />  //input_iterator类型的实现，根据input_iterator_tag的继承关系，forward_iterator<br />  //和bidrectonal_iterator也会调用此实现函数。<br />  while (first != last) { ++first; ++n; }<br />}</font>
		</p>
		<p>
				<font color="#006400">template &lt;class RandomAccessIterator, class Distance&gt;<br />inline void __distance(RandomAccessIterator first, RandomAccessIterator last, <br />                       Distance&amp; n, <strong>random_access_iterator_tag</strong>) <br />{<br />  //random_access_iterator类型的实现<br />  n += last - first;<br />}</font>
		</p>
		<p>                                                                              2004.11.10<br />from: <a href="http://www.zahui.com/html/9/35875.htm">http://www.zahui.com/html/9/35875.htm</a></p>
<img src ="http://www.blogjava.net/weidagang2046/aggbug/71698.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/weidagang2046/" target="_blank">weidagang2046</a> 2006-09-25 11:48 <a href="http://www.blogjava.net/weidagang2046/articles/71698.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>The Standard Librarian: What Are Allocators Good For?</title><link>http://www.blogjava.net/weidagang2046/articles/70038.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Sat, 16 Sep 2006 07:08:00 GMT</pubDate><guid>http://www.blogjava.net/weidagang2046/articles/70038.html</guid><wfw:comment>http://www.blogjava.net/weidagang2046/comments/70038.html</wfw:comment><comments>http://www.blogjava.net/weidagang2046/articles/70038.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/weidagang2046/comments/commentRss/70038.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/weidagang2046/services/trackbacks/70038.html</trackback:ping><description><![CDATA[
		<div class="Bspace15">
				<em>Matthew H. Austern</em>
		</div>
		<!-- teaser -->
		<div class="Bspace15">
				<span class="greenBlurb">Most of us who use the C++ Standard library tend to forget about allocators, those mysterious things specified by default template parameters for STL containers. In most situations you will not need to call an allocator explicitly or write one of your own. But there are occasions when you might want to substitute your own custom allocator for the default version, for example, to allocate objects from a special memory pool. In this column Matt Austern discusses what you can use allocators for and how you can define your own.</span>
		</div>
		<!-- end teaser -->
		<p>
		</p>
		<p>
		</p>
		<hr />
		<p>
		</p>
		<p>Allocators are one of the most mysterious parts of the C++ Standard library. Allocators are rarely used explicitly; the Standard doesn't make it clear when they should ever be used. Today's allocators are substantially different from those in the original STL proposal, and there were two other designs in between — all of which relied on language features that, until recently, were available on few compilers. The Standard appears to make promises about allocator functionality with one hand and then take those promises away with the other.</p>
		<p>This column will discuss what you can use allocators for and how you can define your own. I'm only going to discuss allocators as defined by the C++ Standard: bringing in pre-Standard designs, or workarounds for deficient compilers, would just add to the confusion.</p>
		<p>
		</p>
		<h3>
				<font size="3">When Not to Use Allocators</font>
		</h3>
		<p>
		</p>
		<p>Allocators in the C++ Standard come in two pieces: a set of generic requirements, specified in 20.1.5 (Table 32), and the class <b>std::allocator</b>, specified in 20.4.1. We call a class an allocator if it conforms to the requirements of Table 32. The <b>std::allocator</b> class conforms to those requirements, so it is an allocator. It is the only predefined allocator class in the standard library. 
</p>
		<p>
		</p>
		<p>Every C++ programmer already knows about dynamic memory allocation: you write <b>new X</b> to allocate memory and create a new object of type <b>X</b>, and you write <b>delete p</b> to destroy the object that <b>p</b> points to and return its memory. You might reasonably think that allocators have something to do with <b>new</b> and <b>delete </b>— but they don't. (The Standard describes <b>::operator new</b> as an "allocation function," but, confusingly, that's not the same as an allocator.) 
</p>
		<p>
		</p>
		<p>The most important fact about allocators is that they were intended for one purpose only: encapsulating the low-level details of STL containers' memory management. You shouldn't invoke allocator member functions in your own code, unless you're writing an STL container yourself. You shouldn't try to use allocators to implement <b>operator new[]</b>; that's not what they're for. If you aren't sure whether you need to use allocators, then you don't. 
</p>
		<p>
		</p>
		<p>An allocator is a class with member functions <b>allocate</b> and <b>deallocate</b>, the rough equivalents of <b>malloc</b> and <b>free</b>. It also has helper functions for manipulating the memory that it allocated and typedefs that describe how to refer to the memory — names for pointer and reference types. If an STL container allocates all of its memory through a user-provided allocator (which the predefined STL containers all do; each of them has a template parameter that defaults to <b>std::allocator</b>), you can control its memory management by providing your own allocator. 
</p>
		<p>
		</p>
		<p>This flexibility is limited: a container still decides for itself how much memory it's going to ask for and how the memory will be used. You get to control which low-level functions a container calls when it asks for more memory, but you can't use allocators to make a <b>vector</b> act like a <b>deque</b>. Sometimes, though, even this limited flexibility is useful. If you have a special <b>fast_allocator</b> that allocates and deallocates memory quickly, for example (perhaps by giving up thread safety, or by using a small local heap), you can make the standard list class use it by writing <b>std::list&lt;T, fast_allocator&lt;T&gt; &gt;</b> instead of plain <b>std::list&lt;T&gt;</b>. 
</p>
		<p>
		</p>
		<p>If this seems esoteric to you, you're right. There is no reason to use allocators in normal code. 
</p>
		<p>
		</p>
		<p>
		</p>
		<h3>
				<font size="3">Defining an Allocator</font>
		</h3>
		<p>
		</p>
		<p>This already shows you something about allocators: they're templates. Allocators, like containers, have value types, and an allocator's value type must match the value type of the container it's used with. This can sometimes get ugly: <b>map</b>'s value type is fairly complicated, so a <b>map</b> with an explicit allocator involves expressions like <b>std::map&lt;K, V, fast_allocator&lt;std::pair&lt;const K, V&gt; &gt; &gt;</b>. (As usual, typedefs help.) 
</p>
		<p>
		</p>
		<p>Let's start with a simple example. According to the C++ Standard, <b>std::allocator</b> is built on top of <b>::operator new</b>. If you're using an automatic tool to trace memory usage, it's often more convenient to have something a bit simpler than <b>std::allocator</b>. We can use <b>malloc</b> instead of <b>::operator new</b>, and we can leave out the complicated performance optimizations that you'll find in a good implementation of <b>std::allocator</b>. We'll call this simple allocator <b>malloc_allocator</b>. 
</p>
		<p>
		</p>
		<p>Since the memory management in <b>malloc_allocator</b> is simple, we can focus on the boilerplate that's common to all STL allocators. First, some types: an allocator is a class template, and an instance of that template allocates memory specifically for objects of some type <b>T</b>. We provide a series of typedefs that describe how to refer to objects of that type: <b>value_type</b> for <b>T</b> itself, and others for the various flavors of pointers and references. 
</p>
		<p>
		</p>
		<p>
		</p>
		<pre>template &lt;class T&gt; class malloc_allocator
{
public:
  typedef T                 value_type;
  typedef value_type*       pointer;
  typedef const value_type* const_pointer;
  typedef value_type&amp;       reference;
  typedef const value_type&amp; const_reference;
  typedef std::size_t       size_type;
  typedef std::ptrdiff_t    difference_type;
  ...
};
</pre>It's no accident that these types are so similar to those in an STL container: a container class usually gets those types directly from its allocator. Why so many typedefs? You might think that <b>pointer</b> is superfluous: it's just <b>value_type*</b>. Most of the time that's true, but you might occasionally want to define an unconventional allocator where <b>pointer</b> is some pointer-like class, or where it's some nonstandard vendor-specific type like <b>value_type __far*</b>; allocators are a standard hook for nonstandard extensions. Unusual pointer types are also the reason for the <b>address</b> member function, which in <b>malloc_allocator</b> is just an alternate spelling for <b>operator&amp;</b>: <pre>template &lt;class T&gt; class malloc_allocator
{
public:
  pointer address(reference x) const { return &amp;x; }
  const_pointer address(const_reference x) const { 
    return &amp;x; 
  }
  ...
};
</pre>Now we can get to the real work: <b>allocate</b> and <b>deallocate</b>. They're straightforward, but they don't look quite like <b>malloc</b> and <b>free</b>. We pass two arguments to <b>allocate</b>: the number of objects that we're allocating space for (<b>max_size</b> returns the largest request that might succeed), and, optionally, an address that can be used as a locality hint. A simple allocator like <b>malloc_allocator</b> makes no use of that hint, but an allocator designed for high performance might. The return value is a pointer to a block of memory that's large enough for <b>n</b> objects of type <b>value_type</b> and that has the correct alignment for that type. We also pass two arguments to <b>deallocate</b>: a pointer, of course, but also an element count. A container has to keep track of sizes on its own; the size arguments to <b>allocate</b> and <b>deallocate</b> must match. Again, this extra argument exists for reasons of performance, and again, <b>malloc_allocator</b> doesn't use it. <pre>template &lt;class T&gt; class malloc_allocator 
{
public:
  pointer allocate(size_type n, const_pointer = 0) {
    void* p = std::malloc(n * sizeof(T));
    if (!p)
      throw std::bad_alloc();
    return static_cast&lt;pointer&gt;(p);
  }

  void deallocate(pointer p, size_type) {
    std::free(p);
  }

  size_type max_size() const { 
    return static_cast&lt;size_type&gt;(-1) / sizeof(value_type);
  }
  ...
};
</pre>The <b>allocate</b> and <b>deallocate</b> member functions deal with uninitialized memory; they don't construct or destroy objects. An expression like <b>a.allocate(1)</b> is more like <b>malloc(sizeof(int))</b> than like <b>new int</b>. Before using the memory you get from <b>allocate</b>, you have to create some objects in that memory; before returning that memory with <b>deallocate</b>, you have to destroy those objects. C++ provides a mechanism for creating an object at a specific memory location: placement new. If you write <b>new(p) T(a, b)</b> then you are invoking <b>T</b>'s constructor to create a new object, just as if you had written <b>new T(a, b)</b> or <b>T t(a, b)</b>. The difference is that when you write <b>new(p) T(a, b)</b> you're specifying the location where that object is constructed: the address where <b>p</b> points. (Naturally, <b>p</b> has to point to a large enough region of memory, and it has to point to raw memory; you can't construct two different objects at the same address.) You can also call an object's destructor, without releasing any memory, by writing <b>p-&gt;~T()</b>. These features are rarely used, because usually memory allocation and initialization go together: it's inconvenient and dangerous to work with pointers to uninitialized memory. One of the few places where you need such low-level techniques is if you're writing a container class, so allocators decouple allocation from initialization. The member function <b>construct</b> performs placement new, and the member function <b>destroy</b> invokes the destructor. <pre>template &lt;class T&gt; class malloc_allocator
{
public:
  void construct(pointer p, const value_type&amp; x) { 
    new(p) value_type(x); 
  }
  void destroy(pointer p) { p-&gt;~value_type(); }
  ...
};
</pre>(Why do allocators have those member functions, when containers could use placement new directly? One reason is to hide the somewhat awkward syntax, and another is that if you're writing a more complicated allocator you might want <b>construct</b> and <b>destroy</b> to have some side effects beside object construction and destruction. An allocator might, for example, maintain a log of all currently active objects.) None of these member functions is static, so the first thing a container has to do before using an allocator is create allocator objects — and that means we should define some constructors. We don't need an assignment operator, though: once a container creates its allocator, the allocator isn't ever supposed to be changed. The allocator requirements in Table 32 don't include assignment. Just to be on the safe side, to make sure nobody uses an assignment operator accidentally, we'll disable the one that would otherwise be generated automatically. <pre>template &lt;class T&gt; class malloc_allocator
{
public:
  malloc_allocator() {}
  malloc_allocator(const malloc_allocator&amp;) {}
  ~malloc_allocator() {}
private:
  void operator=(const malloc_allocator&amp;);
  ...
};
</pre>None of these constructors actually does anything, because this allocator doesn't have any member variables to initialize. For the same reason, any two <b>malloc_allocator</b> objects are interchangeable; if <b>a1</b> and <b>a2</b> are both of type <b>malloc_allocator&lt;int&gt;</b>, we can freely allocate memory through <b>a1</b> and deallocate it through <b>a2</b>. We therefore define a comparison operator that says all <b>malloc_allocator</b> objects are equal: <pre>template &lt;class T&gt;
inline bool operator==(const malloc_allocator&lt;T&gt;&amp;, 
                       const malloc_allocator&lt;T&gt;&amp;) {
  return true;
}

template &lt;class T&gt;
inline bool operator!=(const malloc_allocator&lt;T&gt;&amp;, 
                       const malloc_allocator&lt;T&gt;&amp;) {
  return false;
}
</pre>Would you ever want to have an allocator where different objects <i>weren't</i> interchangeable? Certainly — but simple and useful examples are hard to come by. One obvious possibility is memory pools. It's common for large C programs to allocate memory from several different places ("pools"), instead of directly doing everything through <b>malloc</b>. This has several benefits, one of which is that it only takes a single function call to reclaim all of the memory associated with a particular phase of the program. A program that uses memory pools might define utility functions like <b>mempool_Alloc</b> and <b>mempool_Free</b>, where <b>mempool_Alloc(n, p)</b> allocates <b>n</b> bytes from pool <b>p</b>. It's easy to write a <b>mempool_allocator</b> that fits into such a framework: each <b>mempool_allocator</b> object would have a member variable to specify which pool it's associated with, and <b>mempool_allocator::allocate</b> would invoke <b>mempool_Alloc</b> to get memory from the appropriate pool <a href="http://www.ddj.com/dept/cpp/184403759#1">[1]</a>. Finally, we get to the one tricky part of defining an allocator: mapping between different types. The problem is that an allocator class, like <b>malloc_allocator&lt;int&gt;</b>, is all built around a single value type: <b>malloc_allocator&lt;int&gt;::pointer</b> is <b>int*</b>, <b>malloc_allocator&lt;int&gt;().allocate(1)</b> returns enough memory for one <b>int</b> object, and so on. In general, however, a container class that uses <b>malloc_allocator</b> may have to deal with more than one type. A list class, for example, doesn't allocate <b>int</b>s; internally, it allocates list nodes. (We'll see more about that in the next section.) Somehow, when you create an <b>std::list&lt;int, malloc_allocator&lt;int&gt; &gt;</b>, the list has to turn the <b>malloc_allocator&lt;int&gt;</b> into a <b>malloc_allocator</b> for list nodes. The mechanism for this is called <i>rebinding</i>, and it has two parts. First, given an allocator type <b>A1</b> whose value type is <b>X1</b>, you must be able to write down an allocator type <b>A2</b> that's just the same as <b>A1</b> except that its value type is <b>X2</b>. Second, given an object <b>a1</b> of type <b>A1</b>, you must be able to create an equivalent object <b>a2</b> of type <b>A2</b>. Both of these parts use member templates, which is why allocators were unsupported or poorly supported on older compilers. <pre>template &lt;class T&gt; class malloc_allocator
{
public:
  template &lt;class U&gt; 
  malloc_allocator(const malloc_allocator&lt;U&gt;&amp;) {}

  template &lt;class U&gt; 
  struct rebind { typedef malloc_allocator&lt;U&gt; other; };
  ...
};
</pre>What this really means is that an allocator class can't ever just be a single class; it has to be a family of related classes, each with its own value type. An allocator class must always have a <b>rebind</b> member, because that's what makes it possible to go from one class in that family to another. If you have an allocator class <b>A1</b>, the corresponding allocator class for a different value type is <b>typename A1::template rebind&lt;X2&gt;::other</b><a href="http://www.ddj.com/dept/cpp/184403759#2">[2]</a>. And just as you can convert from one type to another, the templatized converting constructor lets you convert values: you can write <b>malloc_allocator&lt;int&gt;(a)</b> whether <b>a</b> is an object of type <b>malloc_allocator&lt;int&gt;</b>, or <b>malloc_allocator&lt;double&gt;</b>, or <b>malloc_allocator&lt;string&gt;</b>. As usual, <b>malloc_allocator</b>'s converting constructor doesn't do anything because <b>malloc_allocator</b> has no member variables. Incidentally, while most allocators have a single template parameter (the allocator's value type) that's not a requirement — it just often happens to be convenient. The rebind mechanism would work just as well for allocators with multiple template parameters: <pre>template &lt;class T, int flags&gt; class my_allocator
{
public:
  template &lt;class U&gt;
  struct rebind { typedef my_allocator&lt;U, flags&gt; other; };
  ...
};
</pre>Finally, one last detail: what do we do about <b>void</b>? Sometimes a container has to refer to void pointers (again, we'll see more about that in the next section), and the rebind mechanism almost gives us what we need, but not quite. It doesn't work, because we would need to write something like <b>malloc_allocator&lt;void&gt;::pointer</b>, and we've defined <b>malloc_allocator</b> in such a way that instantiating it for <b>void</b> would be illegal. It uses <b>sizeof(T)</b>, and it refers to <b>T&amp;</b>; neither is legal when <b>T</b> is <b>void</b>. The solution is as simple as the problem: specialize <b>malloc_allocator</b> for <b>void</b>, leaving out everything except the bare minimum that we need for referring to void pointers. <pre>template&lt;&gt; class malloc_allocator&lt;void&gt;
{
  typedef void        value_type;
  typedef void*       pointer;
  typedef const void* const_pointer;

  template &lt;class U&gt; 
  struct rebind { typedef malloc_allocator&lt;U&gt; other; };
</pre>That's it! The complete source code for <b>malloc_allocator</b> is shown in <a href="http://www.ddj.com/showArticle.jhtml?documentID=cujcexp1812austern&amp;pgno=2">Listing 1</a>. 
<h3><font size="3">Using Allocators</font></h3>The easiest way to use allocators, of course, is to pass them as arguments to container classes; write <pre>std::vector&lt;char, malloc_allocator&lt;char&gt; &gt; V;
</pre>instead of plain <b>std::vector&lt;char&gt;</b>, or <pre>  typedef std::list&lt;int, mempool_allocator&lt;int&gt; &gt; List;
  List L(mempool_allocator&lt;int&gt;(p));
</pre>instead of plain <b>std::list&lt;int&gt;</b>. But you can do more than that. The whole point of the STL is that it's extensible: just as you can write your own allocators, you can also write your own container classes. If you are careful, and if you write a container class that uses its allocator for all memory-related functionality, then somebody else will be able to plug in their own custom-written allocators. Container classes like <b>std::vector</b> and <b>std::list</b> are complicated, and a lot of the complexity has nothing to do with memory management. Let's start with a simple example, so that we can focus just on the allocators. Consider a fixed-size array class, <b>Array</b>, where the number of elements is set in the constructor and can never change thereafter. (This is something like a simplified version of <b>std::valarray</b>.) We'll have two template parameters, the element type and an allocator type. Containers, like allocators, start with nested types: <b>value_type</b>, <b>reference</b>, <b>const_reference</b>, <b>size_type</b>, <b>difference_type</b>, <b>iterator</b>, and <b>const_iterator</b>. In general, most of those types can be taken directly from the container's allocator — thus illustrating why the container's value type and the allocator's must match. The iterator types, of course, don't usually come from the allocator; usually an iterator is some kind of class, closely tied to the container's internal representation. The <b>Array</b> class is simpler than usual because it's natural to store all of our elements in a single contiguous memory block; we'll maintain a pointer to the beginning of the block and a pointer to the end. The iterators will just be pointers. Before we go any further, we have to make a decision: how are we going to store the allocator? The constructor will take an allocator object as one of its arguments. We need to hold on to a copy of the allocator throughout the lifetime of the container, since we'll still need it in the destructor. In some sense, there's no problem here: we could just declare a member variable of type <b>Allocator</b> and be done with it. That solution would be correct, but annoying. Ninety-nine percent of the time, after all, users don't want to bother thinking about allocators; they'll just write <b>Array&lt;int&gt;</b> and use the default — and the default allocator is probably an empty class with no non-static member variables. The trouble is that a member variable of type <b>Allocator</b> will take up even when <b>Allocator</b> is an empty class. (This is required by the C++ Standard.) Our <b>Array</b> class will have three words of overhead, instead of two. Maybe an extra word of overhead isn't a big deal, but it's annoying to burden all users with that overhead for a feature that most of them will never use. There are a number of solutions to this problem, some of which rely on traits classes and partial specialization. Probably the simplest solution is to use a (private) base class of type <b>Allocator</b> instead of a member variable. Compilers are allowed to optimize away empty base classes, and nowadays most compilers do. We can finally write down a skeleton class definition: <pre>template &lt;class T, class Allocator = std::allocator&lt;T&gt; &gt;
class Array : private Allocator
{
public:
  typedef T value_type;
 
  typedef typename Allocator::reference reference;
  typedef typename Allocator::const_reference 
          const_reference;

  typedef typename Allocator::size_type size_type;
  typedef typename Allocator::difference_type 
          difference_type;

  typedef typename Allocator::pointer       iterator;
  typedef typename Allocator::const_pointer const_iterator;

  typedef Allocator allocator_type;
  allocator_type get_allocator() const {
    return static_cast&lt;const Allocator&amp;&gt;(*this);
  }

  iterator begin()             { return first; }
  iterator end()               { return last; }
  const_iterator begin() const { return first; }
  const_iterator end() const   { return last; }

  Array(size_type n = 0, 
        const T&amp; x = T(), 
        const Allocator&amp; a = Allocator());
  Array(const Array&amp;);
  ~Array();

  Array&amp; operator=(const Array&amp;);

private:
  typename Allocator::pointer first;
  typename Allocator::pointer last;
};
</pre>This doesn't yet have all of the boilerplate that we need if we are to satisfy the container requirements (see Table 65, in 23.1 of the C++ Standard, for the complete set of requirements), but most of that boilerplate has little to do with allocators. For our purposes, the most interesting member functions are the constructor, which allocates memory and creates objects, and the destructor, which destroys memory and frees memory. The constructor initializes the allocator base class, obtains a block of memory that's large enough for <b>n</b> elements (if we were writing something like <b>vector</b>, we might obtain a larger block to allow room for growth), and then loops through the block creating copies of the initial value. The only tricky part is exception safety: if one of the elements' constructors throws an exception, we have to undo everything we've done. <pre>template &lt;class T, class Allocator&gt;
Array&lt;T, Allocator&gt;::Array(size_type n, 
                           const T&amp; x, 
                           const Allocator&amp; a)
  : Allocator(a), first(0), last(0)
{
  if (n != 0) {
    first = Allocator::allocate(n);
    size_type i;
    try {
      for (i = 0; i &lt; n; ++i) {
        Allocator::construct(first + i, x);
      }
    }
    catch(...) {
      for(size_type j = 0; j &lt; i; ++j) {
        Allocator::destroy(first + j);
      }
      Allocator::deallocate(first, n);
      throw;
    }
  }
}
</pre>(You might wonder why we're writing out these loops by hand; doesn't <b>std::uninitialized_fill</b> already do what we need? Almost, but not quite. We have to use the allocator's <b>construct</b> member function instead of plain placement new. Perhaps a future version of the C++ Standard will include a version of <b>uninitialized_fill</b> that takes an allocator argument and make such explicit loops unnecessary.) The destructor is simpler, since we don't have to worry about exception safety: <b>T</b>'s destructor is never supposed to throw. <pre>template &lt;class T, class Allocator&gt;
Array&lt;T, Allocator&gt;::~Array() 
{
  if (first != last) {
    for (iterator i = first; i &lt; last; ++i)
      Allocator::destroy(i);
    Allocator::deallocate(first, last - first);
  }
}
</pre>Our simple array class doesn't have to use rebinding or conversion, but that's only because <b>Array&lt;T, Allocator&gt;</b> never creates objects of any type other than <b>T</b>. Other types come in when you define more complicated data structures. Consider, for example, a linked list class whose value type is <b>T</b>. A linked list typically consists of nodes, where each node holds an object of type <b>T</b> and a pointer to the next node. So, as a first attempt, we might define a list node as follows: <pre>template &lt;class T&gt; 
struct List_node
{
  T val;
  List_node* next;
};
</pre>The procedure for adding a new value to the list might look something like this: 
<ul><li>Using an allocator whose value type is <b>List_node&lt;T&gt;</b>, allocate memory for a new list node. 
</li><li>Using an allocator whose value type is <b>T</b>, construct the new list element in the node's <b>val</b> slot. 
</li><li>Link the node into place appropriately.</li></ul>This procedure requires dealing with two different allocators, one of which is obtained from the other via rebinding. It's good enough for almost all applications, even ones that use allocators for quite sophisticated purposes. What it doesn't do is support allocators with unusual pointer types. It explicitly relies on being able to use an ordinary pointer of type <b>List_node&lt;T&gt;*</b>. If you're extremely ambitious, and you want to support allocators with alternative pointer types, everything suddenly becomes much more complicated — the pointer from one list node to another can no longer be of type <b>List_node&lt;T&gt;*</b>, or even of type <b>void*</b>, but must be of some type taken from the allocator. Writing this without circularity is nontrivial: it's illegal to instantiate an allocator with an incomplete type, so there's no way to talk about pointers to <b>List_node</b> until after <b>List_node</b> has been fully defined. We need a delicate chain of declarations. <pre>template &lt;class T, class Pointer&gt;
struct List_node
{
  T val;
  Pointer next;
};

template &lt;class T, class Alloc&gt;
class List : private Alloc
{
private:
  typedef typename Alloc::template rebind&lt;void&gt;::other  
          Void_alloc;
  typedef typename Void_alloc::pointer Voidptr;
  typedef typename List_node&lt;T, Voidptr&gt; Node;
  typedef typename Alloc::template rebind&lt;Node&gt;::other 
          Node_alloc;
  typedef typename Node_alloc::pointer Nodeptr;
  typedef typename Alloc::template rebind&lt;Voidptr&gt;::other
          Voidptr_alloc;

  Nodeptr new_node(const T&amp; x, Nodeptr next) {
    Alloc a = get_allocator();
    Nodeptr p = Node_alloc(a).allocate(1);
    try {
      a.construct(p-&gt;val, x);
    }
    catch(...) {
      Node_alloc(a).deallocate(p, 1);
      throw;
    }
    Voidptr_alloc(a).construct(p-&gt;next, Voidptr(next));
    return p;
  }

  ...
};
</pre><p></p><p>And finally, in case you think that this is far too much effort for far too small a benefit, a reminder: just because you can write a container class that uses allocators doesn't mean that you have to, or that you should. Sometimes you might want to write a container class that relies on a specific allocation strategy, whether it's something as ambitious as a disk-based B-tree container or as simple as the <b>block</b> class that I describe in my book. Even if you do want to write a container class that uses allocators, you don't have to support alternate pointer types. You can write a container where you require that any user-supplied allocator uses ordinary pointers, and document that restriction. Not everything has to be fully general. 
</p><p></p><p></p><h3><font size="3">Future Directions</font></h3><p></p><p>If you want to write a simple allocator like <b>malloc_allocator</b>, you should have no difficulty. (Provided that you're using a reasonably modern compiler, that is.) If you have more ambitious plans, however — a memory pool allocator or an allocator with nonstandard pointer types for distributed computing — the situation is less satisfactory. 
</p><p></p><p>If you want to use some alternative pointer-like type, what operations does it have to support? Must it have a special null value, and, if so, how is that value written? Can you use casts? How can you convert between pointer-like objects and ordinary pointers? Do you have to worry about pointer operations throwing exceptions? I made some assumptions in the last section; the C++ Standard doesn't say whether those assumptions are right or wrong. These details are left to individual standard library implementations, and it's even legal for an implementation to ignore alternative pointer types altogether. The C++ Standard also leaves a few unanswered questions about what happens when different instances of an allocator aren't interchangeable. 
</p><p></p><p>Fortunately, the situation isn't quite as dire as the words in the Standard (20.1.5, paragraphs 4-5) might make it seem. The Standard left some questions unanswered because, at the time it was written, the C++ standardization committee wasn't able to agree on the answers; the necessary experience with allocators did not exist. Everyone involved in writing this section of the Standard considered it to be a temporary patch, and the vagueness will definitely be removed in a future revision. 
</p><p></p><p>For the moment, it's best to stay away from alternative pointer types if you're concerned about portability, but, if you're willing to accept a few limitations, you can safely use allocators like <b>mempool_allocator</b> where the differences between individual objects is important. All major standard library implementations now support such allocators in some way, and the differences between implementations are minor. 
</p><p></p><p>Just as the containers take allocator types as template parameters, so the containers' constructors take allocator objects as arguments. A container makes a copy of that argument and uses the copy for all of its memory management; once it is initialized in the constructor, the container's allocator is never changed. 
</p><p></p><p>The only question is what happens when you perform an operation that requires two containers to cooperate on memory management. There are exactly two such operations in the standard library: <b>swap</b> (all containers) and <b>std::list::splice</b>. In principle, an implementation could handle them in several different ways: 
</p><p></p><p></p><ul><li>Forbid <b>swap</b> or <b>splice</b> between two containers whose allocators aren't equal. 
</li><li>Put a test for allocator equality in <b>swap</b> and <b>splice</b>. If the allocators aren't equal, then fall back to some other operation like copying and assignment. 
</li><li>For <b>swap</b> only: swap the containers' allocators as well as their data. (It's hard to see how we could generalize this to <b>splice</b>. It also presents a problem: how do you swap things that don't have assignment operators?)</li></ul><p></p><p>If you just stay away from <b>swap</b> and <b>splice</b> whenever two containers might be using different allocators, you'll be safe. In practice, I haven't found this to be a serious restriction: you need tight discipline to use a feature like memory pools safely, and you probably won't want indiscriminate mixing between containers with different allocators. 
</p><p></p><p>Partly because of unfamiliarity and partly because of the unsatisfactory state of the C++ Standard's requirements, most uses of allocators today are simple. As the C++ community becomes more familiar with allocators, and as the Standard is clarified, we can expect more sophisticated uses to emerge. 
</p><p></p><p></p><h3><h4><a name="heading1">Listing 1: A sample allocator based on malloc</a></h4><p><font size="3"></font></p><pre><font size="3">template &lt;class T&gt; class malloc_allocator
{
public:
  typedef T                 value_type;
  typedef value_type*       pointer;
  typedef const value_type* const_pointer;
  typedef value_type&amp;       reference;
  typedef const value_type&amp; const_reference;
  typedef std::size_t       size_type;
  typedef std::ptrdiff_t    difference_type;
  
  template &lt;class U&gt; 
  struct rebind { typedef malloc_allocator&lt;U&gt; other; };

  malloc_allocator() {}
  malloc_allocator(const malloc_allocator&amp;) {}
  template &lt;class U&gt; 
  malloc_allocator(const malloc_allocator&lt;U&gt;&amp;) {}
  ~malloc_allocator() {}

  pointer address(reference x) const { return &amp;x; }
  const_pointer address(const_reference x) const { 
    return x;
  }

  pointer allocate(size_type n, const_pointer = 0) {
    void* p = std::malloc(n * sizeof(T));
    if (!p)
      throw std::bad_alloc();
    return static_cast&lt;pointer&gt;(p);
  }

  void deallocate(pointer p, size_type) { std::free(p); }

  size_type max_size() const { 
    return static_cast&lt;size_type&gt;(-1) / sizeof(T);
  }

  void construct(pointer p, const value_type&amp; x) { 
    new(p) value_type(x); 
  }
  void destroy(pointer p) { p-&gt;~value_type(); }

private:
  void operator=(const malloc_allocator&amp;);
};

template&lt;&gt; class malloc_allocator&lt;void&gt;
{
  typedef void        value_type;
  typedef void*       pointer;
  typedef const void* const_pointer;

  template &lt;class U&gt; 
  struct rebind { typedef malloc_allocator&lt;U&gt; other; };
};


template &lt;class T&gt;
inline bool operator==(const malloc_allocator&lt;T&gt;&amp;, 
                       const malloc_allocator&lt;T&gt;&amp;) {
  return true;
}

template &lt;class T&gt;
inline bool operator!=(const malloc_allocator&lt;T&gt;&amp;, 
                       const malloc_allocator&lt;T&gt;&amp;) {
  return false;
}</font></pre></h3><h3><font size="3">Notes</font></h3><p><a name="1"></a>[1] You can see an example of a pool allocator in the open source SGI Pro64<sup>TM</sup> compiler, http://oss.sgi.com/projects/Pro64/. 
</p><p></p><p><a name="2"></a>[2] Why the funny <b>template</b> keyword in that expression? It's an annoying little technicality; like <b>typename</b>, it helps the compiler resolve a parsing ambiguity. The problem is that when <b>A</b> is a template parameter, and the compiler sees an expression like <b>A::B&lt;T&gt;</b>, the compiler doesn't know anything about <b>A</b>'s members. Should it assume that <b>B&lt;T&gt;</b> is a member template, or should it assume that <b>B</b> is an ordinary member variable and that <b>&lt;</b> is just a less than sign? A human reader knows which way to interpret it, but the compiler doesn't. You need to put in <b>template</b> to force the first interpretation. Formally, the rule (in 14.2 of the C++ Standard) is: "When the name of a member template specialization appears after <b>.</b> or <b>-&gt;</b> in a <i>postfix-expression</i>, or after <i>nested-name-specifier</i> in a <i>qualified-id</i>, and the postfix-expression or qualified-id explicitly depends on a template-parameter (14.6.2), the member template name must be prefixed by the keyword <b>template</b>. Otherwise the name is assumed to name a non-template." 
</p><p></p><p></p><p><i><b>Matt Austern</b> is the author of </i>Generic Programming and the STL<i> and the chair of the C++ standardization committee's library working group. He works at AT&amp;T Labs — Research and can be contacted at <a href="mailto:austern@research.att.com">austern@research.att.com</a>.</i></p><p><em></em> </p><img src ="http://www.blogjava.net/weidagang2046/aggbug/70038.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/weidagang2046/" target="_blank">weidagang2046</a> 2006-09-16 15:08 <a href="http://www.blogjava.net/weidagang2046/articles/70038.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Using auto_ptr to Handle Memory</title><link>http://www.blogjava.net/weidagang2046/articles/69527.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Thu, 14 Sep 2006 00:46:00 GMT</pubDate><guid>http://www.blogjava.net/weidagang2046/articles/69527.html</guid><wfw:comment>http://www.blogjava.net/weidagang2046/comments/69527.html</wfw:comment><comments>http://www.blogjava.net/weidagang2046/articles/69527.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/weidagang2046/comments/commentRss/69527.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/weidagang2046/services/trackbacks/69527.html</trackback:ping><description><![CDATA[For instance, it is common to write code such as <pre class="example">void myFunction()
{
    myClass = new myClass();
    // body of function
    delete myClass;
}
</pre>and this may work. But what if somewhere in the function body an <a href="http://cprogramming.com/tutorial/exceptions.html">exception</a> gets thrown? Suddenly, the delete code never gets called! What's more, you may never have intended to throw an exception into the function but one of the functions you call may do so, or you may later need to modify your code to do so. In both cases, this is a memory leak waiting to happen. <br /><br />On the other hand, by letting the auto_ptr class manage your memory for you, as soon as an exception gets thrown and the auto_ptr you declared has gone out of scope, the memory allocated will automatically be freed. First, let's look at how to use auto_ptr, and then I'll explain the exact mechanics of how this works. <br /><br />To take advantage of auto_ptr, you will need to include &lt;memory&gt;. This will give you access to the std <a href="http://www.cprogramming.com/tutorial/namespaces.html">namespace</a>, in which resides the templated class auto_ptr&lt;<i>type</i>&gt;. For <i>type</i>, you should put the type you want your <a href="http://www.cprogramming.com/tutorial/lesson6.html">pointer</a> to point to. For instance, if you would ordinarily have declared an int*, you should use int for the type. When you actually declare an instance of the templated class, the constructor should take a pointer to the specified type. The object will then take care of managing the memory associated with that pointer. For instance, to create an auto_ptr object that manages the memory of a pointer to an integer, you could use this declaration: <pre class="example">std::auto_ptr&lt;int&gt; int_memory_manager(new int);
// Alternately, you could include "using namespace std;" or 
// "using namespace std::auto_ptr" at the top of your code to avoid having to
// prefix all declarations with std::auto_ptr
</pre>To actually use the pointer stored in the auto_ptr container, you can just treat the auto_ptr object you create as though it were the pointer. For instance, you can dereference it: <pre class="example">*int_memory_manager = 5;
</pre>and if you wanted to access a member function (or variable) of a struct or class, you can simply use the same arrow operator as normal. I'll use a fictitious class calle "myClass" to illustrate this. <pre class="example">std::auto_ptr&lt;myClass&gt; myClassManager(new myClass);
myClass-&gt;variable = 50;
</pre>which sets a field called variable to 50 in the instance of myClass whose pointer is stored in myClassManager. <br /><br />The great benefit of all of this is that you simply don't need to worry about calling delete at all! As soon as int_memory_manager goes out of scope, its destructor will be invoked. Its destructor, in turn, will call delete on the pointer. This brings up a subtle point: you must use ato_ptr with memory allocated with new, not malloc, and, moreover, not new[]. Each of these memory allocators must be properly paired: malloc with free, new with delete, and new[] with delete[] (new[] is used to allocate arrays). If they aren't matched correctly, your program may crash. <br /><br />The consequence of auto_ptr's always calling delete on the pointer it stores means that you can't store arrays in an auto_ptr. For instance, the following is a mistake: <pre class="example">std::auto_ptr&lt;int&gt; int_memory_manager(new int[10]);
</pre>What happens when int_memory_manager goes out of scope? The program invokes delete on an array, and this is illegal. Some compilers may let you get away with it, but it's not portable. Just don't do it! If you really need to store a collection of items with constant random access times, just use a <a href="http://www.cprogramming.com/tutorial/stl/vector.html">vector</a> from the <a href="http://www.cprogramming.com/tutorial/stl/stlintro.html">Standard Template Library (STL)</a>. <br /><br />If you just need to retrieve the address of the pointer held in an auto_ptr object, you can use the get method. The following code demonstrates a function that returns a pointer to an integer as stored in an auto_ptr object: <pre class="example">int* example()
{
std::auto_ptr&lt;int&gt; int_memory_manager(new int);
return int_memory_manager.release(); // we'll see release in more depth below 
</pre>Of course, you'd probably be better off simply returning an auto_ptr object in the first place. <br /><br /><b>Some Caveats</b><br /><br />While you can assign one auto_ptr object to another, when you do so, the actual assignment results in the transferral of the pointer from one object to the other. <br /><br />For instance, <pre class="example">std::auto_ptr&lt;int&gt; int_memory_manager(new int);
std::auto_ptr&lt;int&gt; int_memory_manager2;
cout&lt;&lt;"Contents of first is "&lt;&lt;int_memory_manager.get()&lt;&lt;endl;
int_memory_manager2 = int_memory_manager;
cout&lt;&lt;"Contents of first is "&lt;&lt;int_memory_manager.get()&lt;&lt;endl;
cout&lt;&lt;"Contents of second is "&lt;&lt;int_memory_manager2.get()&lt;&lt;endl;
</pre>This sample program demonstrates that the overloaded copy operator for auto_ptr actually removes the pointer from the object being copied! It's set to NULL. This means that only one auto_ptr object can hold a pointer at any time. The act of assigning one auto_ptr to another changes the auto_ptr being assigned. Moreover, this situation holds true even when implicitly copying auto_ptr objects -- for instance, if you make a function call and pass an auto_ptr object, when the function returns, the contents of auto_ptr will be changed to NULL, as demonstrated by the following code: <pre class="example">using namespace std;
void aFunction(std::auto_ptr&lt;int&gt; x)
{
}

int main()
{
    std::auto_ptr&lt;int&gt; int_manager(new int);
    aFunction(int_manager);
    cout&lt;&lt;"Content of int_manager is "int_manager.get()&lt;&lt;endl;
    // Expected output: 0
}
</pre>In truth, this behavior is quite beneficial because it means that two auto_ptr objects will not both try to delete the same pointer. Deleting the same pointer twice is not a valid operation, and can lead to program crashes, whereas deleting NULL is a valid operation (though it doesn't change anything). <br /><br />A subtle consequence of this behavior is that auto_ptrs don't work well in all scenarios. For instance, using auto_ptr objects with the <a href="http://www.cprogramming.com/tutorial/stl/stlintro.html">standard template library</a> can lead to problems as some functions in the STL may make copies of the objects in containers such as the <a href="http://www.cprogramming.com/tutorial/stl/vector.html">vector container class</a>. One example is the sort function, which makes copies of some of the objects in the container being sorted. As a consequence, this copy can blithely delete the data in the container! <br /><br />If for some reason you did want to store an auto_ptr object in an STL container, you should probably either write your own memory manager container that counts the number of references to a pointer or handle freeing the memory somewhere else. If you wanted to take the second approach, you'll need to be able to tell an auto_ptr object that you're finished using it to manage your pointer. You can do this with the release function. For instance, the following code requests that an auto_ptr object allow us to handle the memory for the object again and resets the pointer stored by the auto_ptr object to NULL so that it doesn't get deleted twice. <pre class="example">std::auto_ptr&lt;int&gt; int_memory_manager(new int);
// Calling release sets the pointer managed by int_memory_manager to point 
// to NULL
int *need_to_delete_ptr = int_memory_manager.release();
delete need_to_delete_ptr;
</pre>Finally, if you happen to want to reuse an auto_ptr object, you can simply call the reset function to free the old memory and set the new memory: <pre class="example">std::auto_ptr&lt;int&gt; int_memory_manager(new int);
int_memory_manager.reset(new int);
</pre>Using auto_ptr won't solve all of your problems. First, you could still write code that manually handles pointers that are also managed by auto_ptr objects. Doing this could result in double deletes. Whenever you request manual control of a pointer from an auto_ptr, you open yourself up to the requirement to call delete on that pointer -- consequently, the possibility of a memory leak exists. <br /><br /><b>Summary</b><br /><br />The auto_ptr class is a templated class that takes a type and stores a <a href="http://www.cprogramming.com/tutorial/lesson6.html">pointer</a> of that type, which can be set by the constructor or by using the reset function to pass in a new address to store. Pointers can be returned to manual control by the release function; otherwise, the pointer will be freed when the auto_ptr leaves scope. <br /><br /><b>The Good</b><ul><li>auto_ptr objects store pointers and handle deleting the pointer when the auto_ptr object goes out of scope 
</li><li>Using auto_ptr helps avoid memory leaks associated with exceptions and minimizes the amount of cleanup code required </li></ul><b>The Gotchas</b><ul><li>Copying an auto_ptr changes the object being copied by setting the contests to NULL 
</li><li>auto_ptr objects are not guaranteed to work correctly with the standard template library containers </li></ul><img src ="http://www.blogjava.net/weidagang2046/aggbug/69527.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/weidagang2046/" target="_blank">weidagang2046</a> 2006-09-14 08:46 <a href="http://www.blogjava.net/weidagang2046/articles/69527.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>const使用详解</title><link>http://www.blogjava.net/weidagang2046/articles/63553.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Mon, 14 Aug 2006 16:01:00 GMT</pubDate><guid>http://www.blogjava.net/weidagang2046/articles/63553.html</guid><wfw:comment>http://www.blogjava.net/weidagang2046/comments/63553.html</wfw:comment><comments>http://www.blogjava.net/weidagang2046/articles/63553.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/weidagang2046/comments/commentRss/63553.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/weidagang2046/services/trackbacks/63553.html</trackback:ping><description><![CDATA[
		<div class="comText">一 const基础<br /><br />如果const关键字不涉及到指针，我们很好理解，下面是涉及到指针的情况：<br /><br />int b = 500;<br />const int* a = &amp;b; [1]<br />int const *a = &amp;b; [2]<br />int* const a = &amp;b; [3]<br />const int* const a = &amp;b; [4]<br /><br />如果你能区分出上述四种情况，那么，恭喜你，你已经迈出了可喜的一步。不知道，也没关系，我们可以参考《Effective c++》Item21上的做法，如果const位于星号的左侧，则const就是用来修饰指针所指向的变量，即指针指向为常量；如果const位于星号的右侧，const就是修饰指针本身，即指针本身是常量。因此，[1]和[2]的情况相同，都是指针所指向的内容为常量（const放在变量声明符的位置无关），这种情况下不允许对内容进行更改操作，如不能*a = 3 ；[3]为指针本身是常量，而指针所指向的内容不是常量，这种情况下不能对指针本身进行更改操作，如a++是错误的；[4]为指针本身和指向的内容均为常量。<br />另外const 的一些强大的功能在于它在函数声明中的应用。在一个函数声明中，const 可以修饰函数的返回值，或某个参数；对于成员函数，还可以修饰是整个函数。有如下几种情况，以下会逐渐的说明用法：<br /><br />A&amp; operator=(const A&amp; a);<br />void fun0(const A* a ); <br />void fun1( ) const; // fun1( ) 为类成员函数<br />const A fun2( );<br /><br />二 const的初始化<br /><br />先看一下const变量初始化的情况<br />1) 非指针const常量初始化的情况：<br /><br />A b;<br />const A a = b;<br /><br />2) 指针(引用)const常量初始化的情况：<br /><br />A* d = new A();<br />const A* c = d;<br />或者：const A* c = new A();<br />引用：<br />A f;<br />const A&amp; e = f; // 这样作e只能访问声明为const的函数，而不能访问一般的成员函数；<br /><br />[思考1]： 以下的这种赋值方法正确吗？<br />const A* c=new A();<br />A* e = c;<br />[思考2]： 以下的这种赋值方法正确吗？<br />A* const c = new A();<br />A* b = c;<br /><br />三 作为参数和返回值的const修饰符<br /><br />其实，不论是参数还是返回值，道理都是一样的，参数传入时候和函数返回的时候，初始化const变量<br />1 修饰参数的const，如 void fun0(const A* a ); void fun1(const A&amp; a);<br />调用函数的时候，用相应的变量初始化const常量，则在函数体中，按照const所修饰的部分进行常量化，如形参为const A* a，则不能对传递进来的指针的内容进行改变，保护了原指针所指向的内容；如形参为const A&amp; a，则不能对传递进来的引用对象进行改变，保护了原对象的属性。<br />[注意]：参数const通常用于参数为指针或引用的情况;<br />2 修饰返回值的const，如const A fun2( ); const A* fun3( );<br />这样声明了返回值后，const按照"修饰原则"进行修饰，起到相应的保护作用。<br /><br />const Rational operator*(const Rational&amp; lhs, const Rational&amp; rhs)<br />{<br />return Rational(lhs.numerator() * rhs.numerator(),<br />lhs.denominator() * rhs.denominator());<br />}<br /><br />返回值用const修饰可以防止允许这样的操作发生:<br /><br />Rational a,b;<br />Radional c;<br />(a*b) = c;<br /><br />一般用const修饰返回值为对象本身（非引用和指针）的情况多用于二目操作符重载函数并产生新对象的时候。<br />[总结] 一般情况下，函数的返回值为某个对象时，如果将其声明为const时，多用于操作符的重载。通常，不建议用const修饰函数的返回值类型为某个对象或对某个对象引用的情况。<br />原因如下：<br />如果返回值为某个对象为const（const A test = A 实例）或某个对象的引用为const（const A&amp; test = A实例），则返回值具有const属性，则返回实例只能访问类A中的公有（保护）数据成员和const成员函数，并且不允许对其进行赋值操作，这在一般情况下很少用到。<br /><br />[思考3]： 这样定义赋值操作符重载函数可以吗？<br />const A&amp; operator=(const A&amp; a);<br /><br />四 类成员函数中const的使用<br /><br />一般放在函数体后，形如：void fun() const;<br />如果一个成员函数的不会修改数据成员，那么最好将其声明为const，因为const成员函数中不允许对数据成员进行修改，如果修改，编译器将报错，这大大提高了程序的健壮性。<br /><br />五 使用const的一些建议<br /><br />1 要大胆的使用const，这将给你带来无尽的益处，但前提是你必须搞清楚原委；<br />2 要避免最一般的赋值操作错误，如将const变量赋值，具体可见思考题；<br />3 在参数中使用const应该使用引用或指针，而不是一般的对象实例，原因同上；<br />4 const在成员函数中的三种用法（参数、返回值、函数）要很好的使用；<br />5 不要轻易的将函数的返回值类型定为const;<br />6除了重载操作符外一般不要将返回值类型定为对某个对象的const引用;<br /><br /><br />本人水平有限，欢迎批评指正，可以联系 kangjd@epri.ac.cn<br /><br /><br />[思考题答案]<br />1 这种方法不正确，因为声明指针的目的是为了对其指向的内容进行改变，而声明的指针e指向的是一个常量，所以不正确；<br />2 这种方法正确，因为声明指针所指向的内容可变；<br />3 这种做法不正确；<br />在const A::operator=(const A&amp; a)中，参数列表中的const的用法正确，而当这样连续赋值的时侯，问题就出现了：<br />A a,b,c:<br />(a=b)=c;<br />因为a.operator=(b)的返回值是对a的const引用，不能再将c赋值给const常量。<br /><br />from: <a href="http://www.linux-ren.org/modules/newbb/viewtopic.php?topic_id=1110&amp;forum=14">http://www.linux-ren.org/modules/newbb/viewtopic.php?topic_id=1110&amp;forum=14</a></div>
<img src ="http://www.blogjava.net/weidagang2046/aggbug/63553.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/weidagang2046/" target="_blank">weidagang2046</a> 2006-08-15 00:01 <a href="http://www.blogjava.net/weidagang2046/articles/63553.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>All About: File I/O in C++</title><link>http://www.blogjava.net/weidagang2046/articles/47328.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Sun, 21 May 2006 12:43:00 GMT</pubDate><guid>http://www.blogjava.net/weidagang2046/articles/47328.html</guid><wfw:comment>http://www.blogjava.net/weidagang2046/comments/47328.html</wfw:comment><comments>http://www.blogjava.net/weidagang2046/articles/47328.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/weidagang2046/comments/commentRss/47328.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/weidagang2046/services/trackbacks/47328.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: All About: File I/O in C++																								By 														Ilia Yordanov												, loobian@cpp-home.com																																				www.cpp-home.com...&nbsp;&nbsp;<a href='http://www.blogjava.net/weidagang2046/articles/47328.html'>阅读全文</a><img src ="http://www.blogjava.net/weidagang2046/aggbug/47328.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/weidagang2046/" target="_blank">weidagang2046</a> 2006-05-21 20:43 <a href="http://www.blogjava.net/weidagang2046/articles/47328.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++中动态分配二维数组的方法</title><link>http://www.blogjava.net/weidagang2046/articles/46487.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Tue, 16 May 2006 13:39:00 GMT</pubDate><guid>http://www.blogjava.net/weidagang2046/articles/46487.html</guid><wfw:comment>http://www.blogjava.net/weidagang2046/comments/46487.html</wfw:comment><comments>http://www.blogjava.net/weidagang2046/articles/46487.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/weidagang2046/comments/commentRss/46487.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/weidagang2046/services/trackbacks/46487.html</trackback:ping><description><![CDATA[
		<p>
				<font face="宋体" size="1"> </font>
		</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #000000">#include<br /><br /></span>
				<span style="COLOR: #0000ff">#define</span>
				<span style="COLOR: #000000"> N 4</span>
				<span style="COLOR: #000000">
						<br />typedef </span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> p[N];</span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000">方法一用到</span>
				<span style="COLOR: #008000">
						<br />
				</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #0000ff">using</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">namespace</span>
				<span style="COLOR: #000000"> std;<br /><br /></span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> main()<br />{<br />    </span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> n </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #000000">0</span>
				<span style="COLOR: #000000">;<br /><br />    </span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000">方法一：使用typedef定义一个具有N个元素的数组类型</span>
				<span style="COLOR: #008000">
						<br />
				</span>
				<span style="COLOR: #000000">    p </span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">ptr1;      </span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000">定义二维数组??用法与二维数组相同</span>
				<span style="COLOR: #008000">
						<br />
				</span>
				<span style="COLOR: #000000">    ptr1 </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">new</span>
				<span style="COLOR: #000000"> p[N];<br /><br />    </span>
				<span style="COLOR: #0000ff">for</span>
				<span style="COLOR: #000000">(</span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> i </span>
				<span style="COLOR: #000000">=</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"> N; i</span>
				<span style="COLOR: #000000">++</span>
				<span style="COLOR: #000000">)<br />        </span>
				<span style="COLOR: #0000ff">for</span>
				<span style="COLOR: #000000">(</span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> j </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #000000">0</span>
				<span style="COLOR: #000000">; j </span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000"> N; j</span>
				<span style="COLOR: #000000">++</span>
				<span style="COLOR: #000000">)<br />            ptr1[i][j] </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #000000">++</span>
				<span style="COLOR: #000000">n;<br /><br />    cout </span>
				<span style="COLOR: #000000">&lt;&lt;</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">方法一：</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #000000">&lt;&lt;</span>
				<span style="COLOR: #000000"> endl;<br />    </span>
				<span style="COLOR: #0000ff">for</span>
				<span style="COLOR: #000000">(i </span>
				<span style="COLOR: #000000">=</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"> N; i</span>
				<span style="COLOR: #000000">++</span>
				<span style="COLOR: #000000">)<br />    {<br />        </span>
				<span style="COLOR: #0000ff">for</span>
				<span style="COLOR: #000000">(</span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> j</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">0</span>
				<span style="COLOR: #000000">;j </span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000"> N; j</span>
				<span style="COLOR: #000000">++</span>
				<span style="COLOR: #000000">)<br />            cout </span>
				<span style="COLOR: #000000">&lt;&lt;</span>
				<span style="COLOR: #000000"> ptr1[i][j] </span>
				<span style="COLOR: #000000">&lt;&lt;</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">;<br />        cout </span>
				<span style="COLOR: #000000">&lt;&lt;</span>
				<span style="COLOR: #000000"> endl;<br />    }<br />    delete[] ptr1;<br />    cout </span>
				<span style="COLOR: #000000">&lt;&lt;</span>
				<span style="COLOR: #000000"> endl;<br /><br />    </span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000"> 方法二：使用数组指针</span>
				<span style="COLOR: #008000">
						<br />
				</span>
				<span style="COLOR: #000000">    </span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> row </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> N;     </span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000">二维数组的行数?</span>
				<span style="COLOR: #008000">
						<br />
				</span>
				<span style="COLOR: #000000">    </span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> column </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> N;  </span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000">二维数组的列数<br />     <br />    </span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000">分配一个指针数组，其首地址保存在pMatrix中</span>
				<span style="COLOR: #008000">
						<br />
				</span>
				<span style="COLOR: #000000">    </span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #000000">**</span>
				<span style="COLOR: #000000">pMatrix </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">new</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">[row];<br /><br />    </span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000">为指针数组的每个元素分配一个数组</span>
				<span style="COLOR: #008000">
						<br />
				</span>
				<span style="COLOR: #000000">    </span>
				<span style="COLOR: #0000ff">for</span>
				<span style="COLOR: #000000"> (</span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> i </span>
				<span style="COLOR: #000000">=</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"> row; i</span>
				<span style="COLOR: #000000">++</span>
				<span style="COLOR: #000000">)<br />        pMatrix[i] </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">new</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000">[column];<br /><br />    </span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000">以上是分配，以下是释放</span>
				<span style="COLOR: #008000">
						<br />
				</span>
				<span style="COLOR: #000000">    </span>
				<span style="COLOR: #0000ff">for</span>
				<span style="COLOR: #000000"> (</span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> i </span>
				<span style="COLOR: #000000">=</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"> row; i</span>
				<span style="COLOR: #000000">++</span>
				<span style="COLOR: #000000">)<br />        delete [column] pMatrix[i];<br />    delete [row] pMatrix;<br /><br />    </span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000">这些技术可用于构造一个矩阵类</span>
				<span style="COLOR: #008000">
						<br />
				</span>
				<span style="COLOR: #000000">
						<br />    </span>
				<span style="COLOR: #0000ff">return</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #000000">0</span>
				<span style="COLOR: #000000">;<br />}<br /></span>
		</div>from: <a href="http://www.zahui.com/html/9/20062.htm">http://www.zahui.com/html/9/20062.htm</a><img src ="http://www.blogjava.net/weidagang2046/aggbug/46487.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/weidagang2046/" target="_blank">weidagang2046</a> 2006-05-16 21:39 <a href="http://www.blogjava.net/weidagang2046/articles/46487.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>using Declaration</title><link>http://www.blogjava.net/weidagang2046/articles/34906.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Sun, 12 Mar 2006 05:44:00 GMT</pubDate><guid>http://www.blogjava.net/weidagang2046/articles/34906.html</guid><wfw:comment>http://www.blogjava.net/weidagang2046/comments/34906.html</wfw:comment><comments>http://www.blogjava.net/weidagang2046/articles/34906.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/weidagang2046/comments/commentRss/34906.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/weidagang2046/services/trackbacks/34906.html</trackback:ping><description><![CDATA[<H4>Syntax</H4><PRE class=syntax><B>using</B> [<B>typename</B>][<B>::</B>] <I>nested-name-specifier</I> <I>unqualified-id</I>
<B>using</B> <B>::</B> <I>unqualified-id</I></PRE>
<P>The <B>using</B> declaration introduces a name into the declarative region in which the <B>using</B> declaration appears. The name becomes a synonym for an entity declared elsewhere. It allows an <I>individual</I> name from a specific namespace to be used without <A href="http://msdn.microsoft.com/library/en-us/vccelng/htm/tions_45.asp">explicit qualification</A>. This is in contrast to the <B>using</B> directive, which allows <I>all</I> the names in a namespace to be used without qualification. See <A href="http://msdn.microsoft.com/library/en-us/vccelng/htm/tions_44.asp">using Directive</A> for more information.</P>
<P>A <I>using-declaration</I> can be used in a class definition. For example:</P><PRE>class B
{
    void f(char);
    void g(char);
};

class D : B
{
    using B::f;
    void f(int) { f('c'); }        // calls B::f(char)
    void g(int) { g('c'); }        // recursively calls D::g(int)
                                   // only B::f is being used
};
</PRE>
<P>When used to declare a member, a <I>using-declaration</I> must refer to a member of a base class. For example:</P><PRE>class C
{
    int g();
};

class D2 : public B
{
   