﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-MyMSDN-随笔分类-C/C++</title><link>http://www.cppblog.com/mymsdn/category/7975.html</link><description>MyMSDN记录开发新知道</description><language>zh-cn</language><lastBuildDate>Sun, 20 Mar 2011 12:47:46 GMT</lastBuildDate><pubDate>Sun, 20 Mar 2011 12:47:46 GMT</pubDate><ttl>60</ttl><item><title>关于protobuf中的field_number范围的解释</title><link>http://www.cppblog.com/mymsdn/archive/2011/03/19/142184.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Fri, 18 Mar 2011 18:01:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2011/03/19/142184.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/142184.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2011/03/19/142184.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/142184.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/142184.html</trackback:ping><description><![CDATA[<!--MyMSDN style!--><link rel="stylesheet" type="text/css" href="http://files.cnblogs.com/volnet/gocool.css"> <style type="text/css">
body{background-color:#eeeeee;}
</style>  <div>以下是来自Google Protobuf Documents里的一句话： </div> <div class="quote">As you can see, each field in the message definition has a unique numbered tag. These tags are used to identify your fields in the <a href="http://code.google.com/apis/protocolbuffers/docs/encoding.html">message binary format</a>, and should not be changed once your message type is in use. Note that tags with values in the range 1 through 15 take one byte to encode. Tags in the range 16 through 2047 take two bytes. So you should reserve the tags 1 through 15 for very frequently occurring message elements. Remember to leave some room for frequently occurring elements that might be added in the future. </div> <div>这里要做一个解释，就是为什么是1到15，以及16到2047呢？</div> <div> <ol> <li>1到15，仅使用1bytes。每个byte包含两个部分，一个是field_number一个是tag，其中field-number就是protobuf中每个值后等号后的数字（在C++和Java中，如果不设置这个值，则它是随机的，如果在Python中，不设置，它则不被处理（这个在<a href="http://code.google.com/apis/protocolbuffers/docs/encoding.html">message binary format</a>中的Field Order一节中有提到）。那么我们可以认为这个field_number是必须的。那么一个byte用来表达这个值就是<span style="color: red">0</span><span style="color: blue">00000</span><span style="color: green">000</span>，其中红色表示是否有后续字节，如果为0表示没有也就是这是一个字节，蓝色部分表示field-number，绿色部分则是wire_type部分，表示数据类型。也就是(field_number &lt;&lt; 3) | wire_type。其中wire_type只有3位，表示数据类型。那么能够表示field_number的就是5位蓝色的数字，5位数字能够表达的最大范围就是1-15（其中0是无效的）。  <li>16到2047，与上面的规则其实类似，下面以2bytes为例子，那么就有<span style="color: red">1</span><span style="color: blue">0000000 <span style="color: red">0</span>0000</span><span style="color: green">000</span>，其中红色部分依然是符号位，因为每个byte的第一位都用来表示下一byte是否和自己有关，那么对于>1byte的数据，第一位一定是1，因为这里假设是2byte，那么第二个byte的第一位也是红色，刨除这两位，再扣掉3个wire_type位，剩下11位（2*8-2-3），能够表达的数字范围就是2047（2<sup>11</sup>）。</li></ol></div> <div> 参考资料：<br /> <ol><li>http://code.google.com/intl/zh-CN/apis/protocolbuffers/docs/proto.html</li> <li>http://code.google.com/apis/protocolbuffers/docs/encoding.html</li></ol> </div><img src ="http://www.cppblog.com/mymsdn/aggbug/142184.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2011-03-19 02:01 <a href="http://www.cppblog.com/mymsdn/archive/2011/03/19/142184.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>zig-zag编码方式</title><link>http://www.cppblog.com/mymsdn/archive/2011/03/19/zig-zag-encoding.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Fri, 18 Mar 2011 16:36:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2011/03/19/zig-zag-encoding.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/142182.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2011/03/19/zig-zag-encoding.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/142182.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/142182.html</trackback:ping><description><![CDATA[zig-zag：就是把（-1）1000 0001变成0000 0011，注意最后一个1是符号位，也就是2，那么如果是个int32的话，1000 0000 0000 0000 0000 0000 0000 0001 就变成了000 0000 0000 0000 0000 0000 0000 00011，那么也就是11了，那么可以节约很多符号位。<a  href="http://code.google.com/intl/zh-CN/apis/protocolbuffers/docs/encoding.html">http://goo.gl/2wRKb</a><br>用位运算来表示把一个负数转换成zig-zag编码，就是<span class="pun"><span style="font-family: monospace;"><br></span><br>int32是：(</span><span class="pln">n </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">^</span><span class="pln"> </span><span class="pun">(</span><span class="pln">n </span><span class="pun">&gt;&gt;</span><span class="pln"> </span><span class="lit">31</span>)<br>int64是：<span class="pun">(</span><span class="pln">n </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">^</span><span class="pln"> </span><span class="pun">(</span><span class="pln">n </span><span class="pun">&gt;&gt;</span><span class="pln"> </span><span class="lit">63</span><span class="pun">)</span>
<pre class="prettyprint"><span class="pun">也就是说，如果是负数，对于32位最多能省去30格（其中1格是符号位，另一个代表最小值1，此处假设&#8220;正负0&#8221;不合法）。同理，64位最多能省去62位。当然比较极端的是所有的位数都被用上了。<br></span></pre>
<br><img src ="http://www.cppblog.com/mymsdn/aggbug/142182.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2011-03-19 00:36 <a href="http://www.cppblog.com/mymsdn/archive/2011/03/19/zig-zag-encoding.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>IsWow64并不能用来检测是否是Windows 32bit系统还是64bit系统</title><link>http://www.cppblog.com/mymsdn/archive/2010/09/06/125966.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Sun, 05 Sep 2010 18:06:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2010/09/06/125966.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/125966.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2010/09/06/125966.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/125966.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/125966.html</trackback:ping><description><![CDATA[<p>如何当前操作系统是不是64位？如何判断当前应用程序是否在Wow64下运行？</p> <p>首先什么是Wow64？很多朋友一看到64就认为这个方法是判断当前系统是否是64bit的，其实不然。Wow64是Windows-On-Windows64的意思，它是指在64位的操作系统上（不是指64位的CPU）运行32位应用程序的兼容平台。</p> <p>下面是MSDN中一段IsWow64的应用程序：</p><pre class="gc-code"><span style="color: #010001">BOOL IsWow64</span>() 
{ 
    <span style="color: blue">typedef </span><span style="color: #010001">BOOL </span>(<span style="color: #010001">WINAPI </span>*<span style="color: #010001">LPFN_ISWOW64PROCESS</span>) (<span style="color: #010001">HANDLE</span>, <span style="color: #010001">PBOOL</span>); 
    <span style="color: #010001">LPFN_ISWOW64PROCESS fnIsWow64Process</span>; 
    <span style="color: #010001">BOOL bIsWow64 </span>= <span style="color: #010001">FALSE</span>; 
    <span style="color: #010001">fnIsWow64Process </span>= (<span style="color: #010001">LPFN_ISWOW64PROCESS</span>)<span style="color: #010001">GetProcAddress</span>( <span style="color: #010001">GetModuleHandle</span>(<span style="color: #010001">_T</span>(<span style="color: #a31515">"kernel32"</span>)), <span style="color: #a31515">"IsWow64Process"</span>); 
    <span style="color: blue">if </span>(<span style="color: #010001">NULL </span>!= <span style="color: #010001">fnIsWow64Process</span>) 
    {
        <span style="color: #010001">fnIsWow64Process</span>(<span style="color: #010001">GetCurrentProcess</span>(),&amp;<span style="color: #010001">bIsWow64</span>); 
    } 
    <span style="color: blue">return </span><span style="color: #010001">bIsWow64</span>; 
}</pre>
<p>下面的代码用来检测这个程序的结果：</p><pre class="gc-code"><span style="color: blue">if</span>( <span style="color: #010001">IsWow64</span>() == <span style="color: #010001">TRUE </span>)
{
    <span style="color: #010001">_tprintf</span>(<span style="color: #010001">_T</span>(<span style="color: #a31515">"IsWow64() == TRUE\n"</span>));
}
<span style="color: blue">else
</span>{
    <span style="color: #010001">_tprintf</span>(<span style="color: #010001">_T</span>(<span style="color: #a31515">"IsWow64() == FALSE\n"</span>));
}
</pre>
<p>让我们编译一下这个程序。</p>
<p>我们需要的是64位的操作系统，比如XP64bit，Windows 2008 R2等都是64bit操作系统。</p>
<p>在64位的操作系统上运行的kernel32.dll中，将会实现IsWow64Process方法，而在32位系统中提供的kernel32.dll中则没有提供相关函数的实现。</p>
<p>比较迷惑人的则是bIsWow64，其实仔细看MSDN中的Remark，会发现：</p>
<p>If the application is a 64-bit application running under 64-bit Windows, the <i>Wow64Process</i> parameter is set to FALSE.也就是说64位应用程序跑在64位的操作系统上，bIsWow64的值将是FALSE而不是TRUE。 
<p>因此我们需要分别将我们的程序编译成Win32平台和x64平台的，如果你用Visual Studio进行编译，默认安装则只包含32位的编译器/链接器，即便你是在64位操作系统上安装，也是一样的。你需要在VC++节点下勾选x64选项才可以，Itanium则需要在Server平台下安装才可勾选。然后在编译的时候，分别选择Win32和x64进行编译。 
<p><a href="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/IsWow64Windows32bit64bit_14E3/image_2.png"><img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/IsWow64Windows32bit64bit_14E3/image_thumb.png" width="339" height="92"></a> 
<p>编译后，运行，结果如我们分析的一样： 
<p>在64位系统上运行Win32编译配置的结果是IsWow64() == TRUE，而x64编译配置的结果是IsWow64() == FALSE。 
<p>如果想要知道当前系统是否是64位的，则可以通过下面的方法：</p><pre class="gc-code"><span style="color: #010001">BOOL Is64bitSystem</span>()
{
    <span style="color: #010001">SYSTEM_INFO si</span>;
    <span style="color: #010001">GetNativeSystemInfo</span>(&amp;<span style="color: #010001">si</span>);

    <span style="color: blue">if </span>(<span style="color: #010001">si</span>.<span style="color: #010001">wProcessorArchitecture </span>== <span style="color: #010001">PROCESSOR_ARCHITECTURE_AMD64 </span>||    
        <span style="color: #010001">si</span>.<span style="color: #010001">wProcessorArchitecture </span>== <span style="color: #010001">PROCESSOR_ARCHITECTURE_IA64 </span>)
    {
        <span style="color: blue">return </span><span style="color: #010001">TRUE</span>;
    }
    <span style="color: blue">else
    </span>{
        <span style="color: blue">return </span><span style="color: #010001">FALSE</span>;
    } 
}</pre>
<p>注意：需要注意是GetNativeSystemInfo&nbsp; 函数从Windows XP 开始才有， 而 IsWow64Process&nbsp; 函数从 Windows XP with SP2 以及 Windows Server 2003 with SP1 开始才有。 </p><img src ="http://www.cppblog.com/mymsdn/aggbug/125966.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2010-09-06 02:06 <a href="http://www.cppblog.com/mymsdn/archive/2010/09/06/125966.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>英特尔&amp;reg; 多线程应用开发指南</title><link>http://www.cppblog.com/mymsdn/archive/2010/09/05/125912.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Sat, 04 Sep 2010 18:20:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2010/09/05/125912.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/125912.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2010/09/05/125912.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/125912.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/125912.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: http://software.intel.com/zh-cn/articles/intel-guide-for-developing-multithreaded-applications/ 英特尔® 多线程应用开发指南 提交新文章  Published On :&nbsp; 2010年02月25日 20:00  评级  请登录后评级！当前分数： 0 由 0 用户  请登录后评级！当前分数： 0 ...&nbsp;&nbsp;<a href='http://www.cppblog.com/mymsdn/archive/2010/09/05/125912.html'>阅读全文</a><img src ="http://www.cppblog.com/mymsdn/aggbug/125912.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2010-09-05 02:20 <a href="http://www.cppblog.com/mymsdn/archive/2010/09/05/125912.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]C/C++中动态链接库的创建和调用</title><link>http://www.cppblog.com/mymsdn/archive/2010/08/28/124983.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Fri, 27 Aug 2010 16:30:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2010/08/28/124983.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/124983.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2010/08/28/124983.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/124983.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/124983.html</trackback:ping><description><![CDATA[<p>转载自：<a title="http://developer.51cto.com/art/200702/39608.htm" href="http://developer.51cto.com/art/200702/39608.htm">http://developer.51cto.com/art/200702/39608.htm</a> <p>动态连接库的创建步骤：  <p><strong>一、创建Non-MFC DLL动态链接库</strong>  <p>1、打开File —&gt; New —&gt; Project选项，选择Win32 Dynamic-Link Library —&gt;sample project —&gt;工程名：DllDemo  <p>2、新建一个.h文件DllDemo.h<pre><p>#ifdef DllDemo_EXPORTS <br>#define DllAPI __declspec(dllexport) <br>#else <br>#define DllAPI __declspec(dllimport) <br>extern "C" //原样编译 <br>{ <br>DllAPI int __stdcall Max(int a,int b); //__stdcall使非C/C++语言内能够调用API <br>} <br>#endif</p></pre>
<p>3、在DllDemo.cpp文件中导入DllDemo.h文件，并实现Max(int,int)函数<pre><p>#include "DllDemo.h" <br>DllAPI int __stdcall Max(int a,int b) <br>{ <br>if(a==b) <br>return NULL; <br>else if(a&gt;b) <br>return a; <br>else <br>return b; <br>}</p></pre>
<p>4、编译程序生成动态连接库 
<p><strong>二、用.def文件创建动态连接库DllDemo.dll</strong> 
<p>1、删除DllDemo工程中的DllDemo.h文件。 
<p>2、在DllDemo.cpp文件头，删除 #include DllDemo.h语句。 
<p>3、向该工程中加入一个文本文件，命名为DllDemo.def并写入如下语句： 
<p>LIBRARY MyDll 
<p>EXPORTS 
<p>Max@1 
<p>4、编译程序生成动态连接库。 
<p><strong>动态链接的调用步骤：</strong> 
<p><strong>一、隐式调用</strong> 
<p>1、建立DllCnslTest工程 
<p>2、将文件DllDemo.dll、DllDemo.lib拷贝到DllCnslTest工程所在的目录 
<p>3、在DllCnslTest.h中添加如下语句：<pre><p>#define DllAPI __declspec(dllimport) <br>#pragma comment(lib，"DllDemo.lib") //在编辑器link时，链接到DllDemo.lib文件 <br>extern "C" <br>{ <br>DllAPI int __stdcall Max(int a,int b); <br>}</p></pre>
<p>4、在DllCnslTest.cpp文件中添加如下语句：<pre><p>#include "DllCnslTest.h"//或者 #include "DllDemo.h" <br>void main() <br>{ <br>int value; <br>value = Max(2,9); <br>printf("The Max value is %d\n",value); <br>}</p></pre>
<p>5、编译并生成应用程序DllCnslTest.exe 
<p><strong>二、显式调用</strong> 
<p>1、建立DllWinTest工程。 
<p>2、将文件DllDemo.dll拷贝到DllWinTest工程所在的目录或Windows系统目录下。 
<p>3、用vc/bin下的Dumpbin.exe的小程序，查看DLL文件(DllDemo.dll)中的函数结构。 
<p>4、使用类型定义关键字typedef，定义指向和DLL中相同的函数原型指针。 
<p>例：<pre><p>typedef int(*lpMax)(int a,int b); //此语句可以放在.h文件中</p></pre>
<p>5、通过LoadLibray()将DLL加载到当前的应用程序中并返回当前DLL文件的句柄。 
<p>例：<pre><p>HINSTANCE hDll; //声明一个Dll实例文件句柄 <br>hDll = LoadLibrary("DllDemo.dll");//导入DllDemo.dll动态连接库</p></pre>
<p>6、通过GetProcAddress()函数获取导入到应用程序中的函数指针。 
<p>例：<pre><p>lpMax Max; <br>Max = (lpMax)GetProcAddress(hDLL,"Max"); <br>int value; <br>value = Max(2,9); <br>printf("The Max value is %d",value);</p></pre>
<p>7、函数调用完毕后，使用FreeLibrary()卸载DLL文件。<pre><p>FreeLibrary(hDll);</p></pre>
<p>8、编译并生成应用程序DllWinTest.exe 
<p>注：显式链接应用程序编译时不需要使用相应的Lib文件。</p>
<p>下载（<font style="background-color: #cccccc"></font><font color="#cccccc">Visual Studio 2008验证通过</font><font style="background-color: #cccccc"></font>）：<a title="http://www.cppblog.com/Files/mymsdn/DllCnsTest.7z" href="http://www.cppblog.com/Files/mymsdn/DllCnsTest.7z">http://www.cppblog.com/Files/mymsdn/DllCnsTest.7z</a></p><img src ="http://www.cppblog.com/mymsdn/aggbug/124983.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2010-08-28 00:30 <a href="http://www.cppblog.com/mymsdn/archive/2010/08/28/124983.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>两个有用的宏：&amp;ldquo;禁止类成员复制&amp;rdquo;以及&amp;ldquo;禁止隐式构造&amp;rdquo;</title><link>http://www.cppblog.com/mymsdn/archive/2010/08/11/123003.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Tue, 10 Aug 2010 16:34:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2010/08/11/123003.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/123003.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2010/08/11/123003.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/123003.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/123003.html</trackback:ping><description><![CDATA[<p>禁止类成员复制，其核心就在于不允许类外部看见复制函数，包括&#8220;拷贝构造函数&#8221;、&#8220;operator =重载&#8221;。</p>
<pre class="gc-code">#define DISALLOW_COPY_AND_ASSIGN(TypeName) \<br><span style="color: #0000ff;">private</span>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>TypeName(<span style="color: #0000ff;">const</span> TypeName&amp;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>TypeName&amp; <span style="color: #0000ff;">operator</span>=(<span style="color: #0000ff;">const</span> TypeName&amp;)</pre>
禁止隐式构造，则可以将默认构造函数隐藏起来，在大多数编译器中也可以对构造函数增加explicit关键字来避免隐式构造。
<pre class="gc-code">#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \<br><span style="color: #0000ff;">private</span>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>TypeName();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>DISALLOW_COPY_AND_ASSIGN(TypeName)</pre>
更多解释详见《More Effective C++》  <img src ="http://www.cppblog.com/mymsdn/aggbug/123003.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2010-08-11 00:34 <a href="http://www.cppblog.com/mymsdn/archive/2010/08/11/123003.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[C++]__declspec关键字</title><link>http://www.cppblog.com/mymsdn/archive/2010/07/22/121059.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Thu, 22 Jul 2010 12:46:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2010/07/22/121059.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/121059.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2010/07/22/121059.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/121059.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/121059.html</trackback:ping><description><![CDATA[<p><span style="color: blue">__declspec</span>关键字</p><pre class="gc-code"><span style="color: green">// keyword__declspec.cpp : 定义控制台应用程序的入口点。
//

// ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/kernel_d/hh/Kernel_d/64bitAMD_6db3322a-fe6d-4287-9eda-a9c1378e715d.xml.htm
// The sizeof value for any structure is the offset of the final member, 
//  plus that member's size, rounded up to the nearest multiple of the largest 
//  member alignment value or the whole structure alignment value, 
//  whichever is greater. 

</span><span style="color: blue">#include </span><span style="color: #a31515">"stdafx.h"

</span><span style="color: blue">__declspec</span>( <span style="color: blue">align</span>( 32) ) <span style="color: blue">struct </span><span style="color: #010001">Struct__declspec_1
</span>{
    <span style="color: blue">int </span><span style="color: #010001">a</span>;
    <span style="color: blue">int </span><span style="color: #010001">b</span>;
};

<span style="color: blue">__declspec</span>( <span style="color: blue">align</span>( 32) ) <span style="color: blue">struct </span><span style="color: #010001">Struct__declspec_2
</span>{
    <span style="color: blue">__declspec</span>( <span style="color: blue">align</span>( 64) ) <span style="color: blue">int </span><span style="color: #010001">a</span>;
    <span style="color: blue">int </span><span style="color: #010001">b</span>;
};

<span style="color: blue">__declspec</span>( <span style="color: blue">align</span>( 8 ) ) <span style="color: blue">struct </span><span style="color: #010001">Struct__declspec_3
</span>{
    <span style="color: blue">int </span><span style="color: #010001">a</span>;  <span style="color: green">//4 bytes
    </span><span style="color: blue">int </span><span style="color: #010001">b</span>;  <span style="color: green">//4 bytes
    </span><span style="color: blue">int </span><span style="color: #010001">c</span>;  <span style="color: green">//4 bytes
</span>};

<span style="color: blue">__declspec</span>( <span style="color: blue">align</span>( 8 ) ) <span style="color: blue">struct </span><span style="color: #010001">Struct__declspec_4
</span>{
    <span style="color: blue">int </span><span style="color: #010001">a</span>;  <span style="color: green">//4 bytes
    </span><span style="color: blue">int </span><span style="color: #010001">b</span>;  <span style="color: green">//4 bytes
</span>};

<span style="color: blue">struct </span><span style="color: #010001">StructNormal
</span>{
    <span style="color: blue">int </span><span style="color: #010001">a</span>;  <span style="color: green">//4 bytes
    </span><span style="color: blue">int </span><span style="color: #010001">b</span>;  <span style="color: green">//4 bytes
    </span><span style="color: blue">int </span><span style="color: #010001">c</span>;  <span style="color: green">//4 bytes
</span>};

<span style="color: blue">int </span><span style="color: #010001">_tmain</span>(<span style="color: blue">int </span><span style="color: #010001">argc</span>, <span style="color: #010001">_TCHAR</span>* <span style="color: #010001">argv</span>[])
{
    <span style="color: #010001">printf</span>( <span style="color: #a31515">"sizeof Struct__declspec_1 is %d.\n"</span>, <span style="color: blue">sizeof</span>( <span style="color: #010001">Struct__declspec_1 </span>));    <span style="color: green">//32
    </span><span style="color: #010001">printf</span>( <span style="color: #a31515">"sizeof Struct__declspec_2 is %d.\n"</span>, <span style="color: blue">sizeof</span>( <span style="color: #010001">Struct__declspec_2 </span>));    <span style="color: green">//64
    </span><span style="color: #010001">printf</span>( <span style="color: #a31515">"sizeof Struct__declspec_3 is %d.\n"</span>, <span style="color: blue">sizeof</span>( <span style="color: #010001">Struct__declspec_3 </span>));    <span style="color: green">//16
    </span><span style="color: #010001">printf</span>( <span style="color: #a31515">"sizeof Struct__declspec_4 is %d.\n"</span>, <span style="color: blue">sizeof</span>( <span style="color: #010001">Struct__declspec_4 </span>));    <span style="color: green">//8

    </span><span style="color: #010001">printf</span>( <span style="color: #a31515">"sizeof StructNormal is %d.\n"</span>, <span style="color: blue">sizeof</span>( <span style="color: #010001">StructNormal </span>));    <span style="color: green">//12
    </span><span style="color: blue">return </span>0;
}

</pre><img src ="http://www.cppblog.com/mymsdn/aggbug/121059.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2010-07-22 20:46 <a href="http://www.cppblog.com/mymsdn/archive/2010/07/22/121059.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[C++]内存管理（1）</title><link>http://www.cppblog.com/mymsdn/archive/2010/07/06/memory_manager-1.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Tue, 06 Jul 2010 14:45:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2010/07/06/memory_manager-1.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/119492.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2010/07/06/memory_manager-1.html#Feedback</comments><slash:comments>17</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/119492.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/119492.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 和大多数内存管理的初衷一致，希望能够控制内存分配和回收，减少内存碎片，且通常这样的内存都会预开一段连续内存空间，然后我们自己来管理这段内存。当然通常这样的需求都很合理，但是实现起来则通常不能完美，比如：效率、算法的选择、如何减少内存碎片、跟踪管理内存分配、性能检测、对系统内存使用的统计、垃圾回收等。下面是我近期实现的一个非常简陋的程序，甚至可能连基本的要求都无法达到，大家帮忙看看，它究竟有多少缺点...&nbsp;&nbsp;<a href='http://www.cppblog.com/mymsdn/archive/2010/07/06/memory_manager-1.html'>阅读全文</a><img src ="http://www.cppblog.com/mymsdn/aggbug/119492.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2010-07-06 22:45 <a href="http://www.cppblog.com/mymsdn/archive/2010/07/06/memory_manager-1.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>编译旧程序的时候，可能需要手动关闭UAC选项，否则可能程序无法运行</title><link>http://www.cppblog.com/mymsdn/archive/2010/07/02/119127.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Thu, 01 Jul 2010 17:14:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2010/07/02/119127.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/119127.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2010/07/02/119127.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/119127.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/119127.html</trackback:ping><description><![CDATA[<p>今天在VS2008下编译VS自带Sample中的一个例子，TstCon，因为之前的机器装的是XP系统，该程序曾成功编译过，不过今天在Windows Server 2008 R2下打开失败，在朋友的Windows 7 Ultimate下打开也失败，试用以管理员身份运行，失败，试用修改兼容性选项为Windows XP SP3/SP2方式，均失败。</p> <p>其实这个时候可能是一些Vista以上版本的OS所提供的新功能引起的限制。就当前的这个例子而言，是因为编译的时候，启用用户帐户控制(UAC)默认为“是”所致，将解决方案内所有工程选中，右键属性，修改“配置属性”-&gt;“链接器”-&gt;“清单文件”-&gt;“启用用户帐户控制(UAC)”为“否”，重新生成解决方案，即可。</p> <p><a href="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/f6ec3fce6e75_FC5/image_2.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" class="wlDisabledImage" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/f6ec3fce6e75_FC5/image_thumb.png" width="770" height="564"></a></p><img src ="http://www.cppblog.com/mymsdn/aggbug/119127.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2010-07-02 01:14 <a href="http://www.cppblog.com/mymsdn/archive/2010/07/02/119127.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>size_t的倒序遍历问题</title><link>http://www.cppblog.com/mymsdn/archive/2010/06/30/119021.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Wed, 30 Jun 2010 15:51:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2010/06/30/119021.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/119021.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2010/06/30/119021.html#Feedback</comments><slash:comments>11</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/119021.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/119021.html</trackback:ping><description><![CDATA[<p>准确地说还是经验不足，这么简单的事居然想了好几分钟，当然也要怪VS在没有重新生成前的诡异现象。</p> <p>今晚在类中加入两个数组用来做计数，因为之前代码有所改动，VS编译（增量）的结果居然出现了无数次的程序崩溃，害我一度怀疑是不是我的数组写的有问题。囧。最后无奈之下，点了重新生成，居然顺利通过了，很生气，愤怒中。</p> <p>但是另外却发现了一个问题，也就是当size_t用作循环的时候。因为以前都是用int做循环的，现在换成unsigned int（也就是size_t）后，一下子没反应过来，就顺手这么写了：</p> <div class="gc-code">&nbsp; <p>for( size_t i = MAX - 1; i &gt;= 0; --i)</p> <p>{</p> <blockquote> <p>//……</p></blockquote> <p>}</p></div> <p>乍一看似乎没啥问题，因为我循环内的代码是删除资源的，因此程序也频频崩溃。</p> <p>step over的结果才让人惊讶，因为当size_t i = 0的时候，--i的结果是无穷大，而无穷大则肯定满足i&gt;=0的条件，所以当我们期待程序停住的时候，程序是不会停住的。</p> <p>修正的方式：</p> <p>1、使用正向遍历。</p> <p>2、增加判断条件（i&gt;=0 &amp;&amp; i &lt; MAX），但这里也可能存在问题，因为size_t可能被定义为unsigned int，但是MAX可能是个更大的数，比如unsigned long long，当然这样的比较不是很有意义，或者会实现一些转换，但是如果这种情况发生的话，程序可能还是会通过一个随机的i进入到一个未知的空间中，从而造成崩溃。而且增加判断条件也使得程序的运行成本提高。</p><img src ="http://www.cppblog.com/mymsdn/aggbug/119021.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2010-06-30 23:51 <a href="http://www.cppblog.com/mymsdn/archive/2010/06/30/119021.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ Traits</title><link>http://www.cppblog.com/mymsdn/archive/2010/04/26/cpp-traits.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Mon, 26 Apr 2010 07:31:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2010/04/26/cpp-traits.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/113597.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2010/04/26/cpp-traits.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/113597.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/113597.html</trackback:ping><description><![CDATA[<p>本来想好好写写C++ Traits的，刚刚接到interview的通知，先贴代码，改天再议。</p><pre class="gc-code"><span style="color: #3f7f5f">/*
 * cpp_traits.cpp
 *
 *  Created on: 2010-4-26
 *      Author: volnet@tom.com
 */
</span><span style="color: #7f0055">#include </span><span style="color: #2a00ff">&lt;iostream&gt;
</span><span style="color: #3f7f5f">// kinds of types for overloading.
</span><span style="color: #7f0055">struct </span><span style="color: #005032">undefined_type </span>{};
<span style="color: #7f0055">struct </span><span style="color: #005032">int32_type </span>{};
<span style="color: #7f0055">struct </span><span style="color: #005032">int64_type </span>{};

<span style="color: #3f7f5f">// typedef some has_trivial_* for difference types.
</span><span style="color: #7f0055">template </span>&lt;<span style="color: #7f0055">class </span><span style="color: #644632">T</span>&gt;
<span style="color: #7f0055">struct </span><span style="color: #005032">type_traits </span>{
    <span style="color: #7f0055">typedef </span><span style="color: #005032">undefined_type has_trivial_type</span>;
};

<span style="color: #3f7f5f">// define the partial specialization functions.
</span><span style="color: #7f0055">template </span>&lt;&gt;
<span style="color: #7f0055">struct </span><span style="color: #005032">type_traits</span>&lt;<span style="color: #7f0055">int</span>&gt; {
    <span style="color: #7f0055">typedef </span><span style="color: #005032">int32_type has_trivial_type</span>;
};
<span style="color: #7f0055">template </span>&lt;&gt;
<span style="color: #7f0055">struct </span><span style="color: #005032">type_traits</span>&lt;<span style="color: #7f0055">long</span>&gt; {
    <span style="color: #7f0055">typedef </span><span style="color: #005032">int64_type has_trivial_type</span>;
};

<span style="color: #3f7f5f">// the dispatcher method for all kinds of types.
</span><span style="color: #7f0055">template </span>&lt;<span style="color: #7f0055">class </span><span style="color: #644632">T</span>&gt;
<span style="color: #7f0055">void </span>type_detect(<span style="color: #644632">T</span>&amp; p){
    <span style="color: #7f0055">typedef typename </span><span style="color: #005032">type_traits</span>&lt;<span style="color: #644632">T</span>&gt;::<span style="color: #005032">has_trivial_type trivial_type</span>;
    type_detect(p, <span style="color: #005032">trivial_type</span>());
}

<span style="color: #3f7f5f">// define the functions for dispatching.
</span><span style="color: #7f0055">template </span>&lt;<span style="color: #7f0055">class </span><span style="color: #644632">T</span>&gt;
<span style="color: #7f0055">void </span>type_detect(<span style="color: #644632">T</span>&amp; p, <span style="color: #005032">undefined_type</span>) {
    std::cout &lt;&lt; p;
    std::cout &lt;&lt; <span style="color: #2a00ff">" // It's a undefined type, we have NOT found the dispatcher function." </span>&lt;&lt; std::endl;
}
<span style="color: #7f0055">template </span>&lt;<span style="color: #7f0055">class </span><span style="color: #644632">T</span>&gt;
<span style="color: #7f0055">void </span>type_detect(<span style="color: #644632">T</span>&amp; p, <span style="color: #005032">int32_type</span>) {
    std::cout &lt;&lt; p;
    std::cout &lt;&lt; <span style="color: #2a00ff">" // It's a int32" </span>&lt;&lt; std::endl;
}
<span style="color: #7f0055">template </span>&lt;<span style="color: #7f0055">class </span><span style="color: #644632">T</span>&gt;
<span style="color: #7f0055">void </span>type_detect(<span style="color: #644632">T</span>&amp; p, <span style="color: #005032">int64_type</span>) {
    std::cout &lt;&lt; p;
    std::cout &lt;&lt; <span style="color: #2a00ff">" // It's a int64" </span>&lt;&lt; std::endl;
}

<span style="color: #7f0055">int </span>main(<span style="color: #7f0055">void</span>) {
    <span style="color: #7f0055">int </span>int32num = 2010;
    type_detect(int32num);

    <span style="color: #7f0055">long </span>int64num = 2010L;
    type_detect(int64num);

    std::<span style="color: #005032">string </span>str = <span style="color: #2a00ff">"2010"</span>;
    type_detect(str);

    std::cout &lt;&lt; <span style="color: #2a00ff">"-------end of program." </span>&lt;&lt; std::endl;
    <span style="color: #7f0055">return </span>EXIT_SUCCESS;
}
</pre><a href="http://11011.net/software/vspaste"></a><img src ="http://www.cppblog.com/mymsdn/aggbug/113597.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2010-04-26 15:31 <a href="http://www.cppblog.com/mymsdn/archive/2010/04/26/cpp-traits.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[翻译]高效使用auto_ptr</title><link>http://www.cppblog.com/mymsdn/archive/2010/04/07/Using-auto_ptr-Effectively.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Wed, 07 Apr 2010 11:08:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2010/04/07/Using-auto_ptr-Effectively.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/111882.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2010/04/07/Using-auto_ptr-Effectively.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/111882.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/111882.html</trackback:ping><description><![CDATA[<h4><i>本文来自C/C++用户日志，17（10），1999年10月</i>&nbsp; <a href="http://www.gotw.ca/publications/using_auto_ptr_effectively.htm">原文链接</a></h4> <p>大部分人都听说过auto_ptr指针，但是并非所有人都每天使用它。不使用它是不明智的（可耻的），因为auto_ptr的设计初衷是为了解决C++设计和编码的普遍问题，将它用好可以写出更健壮的代码。本文指出如何正确使用auto_ptr以使程序变得安全，以及如何避开危险，而不是一般使用auto_ptr的恶习所致的创建间歇性和难以诊断的问题。 </p> <h3>为什么它是一个“自动”指针 </h3> <p>auto_ptr只是许许多多智能指针中的一种。许多商业库提供许多更强大的智能指针，可以完成更多的事情。从可以管理引用计数到提供更先进的代理服务等。应该把auto_ptr认为是智能指针中的福特Escort[<a href="http://en.wikipedia.org/wiki/Ford_Escort_%28North_America%29" alt="go to wiki">注释</a>]：一个基于简单且通用目的的智能指针，既没有小发明也没有丰富的特殊目的更不需要高性能，但是能将许多普通的事情做好，并且能够适合日常使用的智能指针。 </p> <p>auto_ptr做这样一件事：拥有一个动态分配内存对象，并且在它不再需要的时候履行自动清理的职责。这里有个没有使用auto_ptr指针的不安全的例子： </p> <p><pre class="gc-code">    <span style="color: #008000">// Example 1(a): Original code</span>
    <span style="color: #008000">//</span>
    <span style="color: #0000ff">void</span> f()
    {
      T* pt( <span style="color: #0000ff">new</span> T );

      <span style="color: #008000">/*...more code...*/</span>

      <span style="color: #0000ff">delete</span> pt;
    }</pre>
<p></p>
<p>我们每天都像这样写代码，如果f()只是一个三行程序，也没做什么多余的事情，这样做当然可以很好工作。但是如果f()没有执行delete语句，比如程序提前返回（return）了，或者在执行的时候抛出异常了，然后就导致已经分配的对象没有被删除，因此我们就有了一个经典的内存泄漏。 </p>
<p>一个使Example（1）安全的办法是用一个“智能”的指针拥有这个指针，当销毁的时候，删除那个被指的自动分配的对象。因为这个智能指针被简单地用为自动对象（这就是，当它离开它的作用域的时候自动销毁对象），所以它被称作“自动”指针。 </p>
<p><pre class="gc-code">    <span style="color: #008000">// Example 1(b): Safe code, with auto_ptr</span>
    <span style="color: #008000">//</span>
    <span style="color: #0000ff">void</span> f()
    {
      auto_ptr&lt;T&gt; pt( <span style="color: #0000ff">new</span> T );

      <span style="color: #008000">/*...more code...*/</span>

    } <span style="color: #008000">// cool: pt's destructor is called as it goes out</span>
      <span style="color: #008000">// of scope, and the object is deleted automatically</span></pre>
<p></p>
<p>现在这段代码将不会再T对象上发生泄漏了，不必在意这个方法是正常退出还是异常退出，因为pt的析构函数将总是在堆栈弹出的时候被调用。清理工作将自动进行。</p>
<p>最后，使用auto_ptr和使用内建指针一样地容易，如果要“收回”资源并且再次手动管理的话，我们可以调用release()：</p><pre class="gc-code">    <span style="color: #008000">// Example 2: Using an auto_ptr</span>
    <span style="color: #008000">//</span>
    <span style="color: #0000ff">void</span> g()
    {
      T* pt1 = <span style="color: #0000ff">new</span> T;
      <span style="color: #008000">// right now, we own the allocated object</span>

      <span style="color: #008000">// pass ownership to an auto_ptr</span>
      auto_ptr&lt;T&gt; pt2( pt1 );

      <span style="color: #008000">// use the auto_ptr the same way</span>
      <span style="color: #008000">// we'd use a simple pointer</span>
      *pt2 = 12;       <span style="color: #008000">// same as "*pt1 = 12;"</span>
      pt2-&gt;SomeFunc(); <span style="color: #008000">// same as "pt1-&gt;SomeFunc();"</span>

      <span style="color: #008000">// use get() to see the pointer value</span>
      assert( pt1 == pt2.get() );

      <span style="color: #008000">// use release() to take back ownership</span>
      T* pt3 = pt2.release();

      <span style="color: #008000">// delete the object ourselves, since now</span>
      <span style="color: #008000">// no auto_ptr owns it any more</span>
      <span style="color: #0000ff">delete</span> pt3;

    } <span style="color: #008000">// pt2 doesn't own any pointer, and so won't</span>
      <span style="color: #008000">// try to delete it... OK, no double delete</span></pre>
<p>最后，我们可以使用auto_ptr的reset()方法将auto_ptr重置向另一个对象。如果auto_ptr已经获得一个对象，这个过程就像是它先删除已经拥有的对象，因此调用reset()，就像是先销毁了auto_ptr，然后重建了一个新的并拥有该新对象： </p>
<p><pre class="gc-code">    <span style="color: #008000">// Example 3: Using reset()</span>
    <span style="color: #008000">//</span>
    <span style="color: #0000ff">void</span> h()
    {
      auto_ptr&lt;T&gt; pt( <span style="color: #0000ff">new</span> T(1) );

      pt.reset( <span style="color: #0000ff">new</span> T(2) );
        <span style="color: #008000">// deletes the first T that was</span>
        <span style="color: #008000">// allocated with "new T(1)"</span>

    } <span style="color: #008000">// finally, pt goes out of scope and</span>
      <span style="color: #008000">// the second T is also deleted</span></pre>
<p></p>
<h3>包装指针数据成员</h3>
<p>同样，auto_ptr也可以被用于安全地包装指针数据成员。考虑下面使用Pimpl idiom（或者，编译器防火墙）的例子：<sup>[<a href="#1">1</a>]</sup></p>
<p><pre class="gc-code">    <span style="color: #008000">// Example 4(a): A typical Pimpl</span>
    <span style="color: #008000">//</span>

    <span style="color: #008000">// file c.h</span>
    <span style="color: #008000">//</span>
    <span style="color: #0000ff">class</span> C
    {
    <span style="color: #0000ff">public</span>:
      C();
      ~C();
      <span style="color: #008000">/*...*/</span>
    <span style="color: #0000ff">private</span>:
      <span style="color: #0000ff">class</span> CImpl; <span style="color: #008000">// forward declaration</span>
      CImpl* pimpl_;
    };

    <span style="color: #008000">// file c.cpp</span>
    <span style="color: #008000">//</span>
    <span style="color: #0000ff">class</span> C::CImpl { <span style="color: #008000">/*...*/</span> };

    C::C() : pimpl_( <span style="color: #0000ff">new</span> CImpl ) { }
    C::~C() { <span style="color: #0000ff">delete</span> pimpl_; }</pre>
<p></p>
<p>简单地说，就是C的私有细节被实现为一个单独的对象，藏匿于一个指针之中。该思路要求C的构造函数负责为隐藏在类内部的辅助“Pimpl”对象分配内存，并且C的析构函数负责销毁它。使用auto_ptr，我们会发现这非常容易： </p>
<p><pre class="gc-code">    <span style="color: #008000">// Example 4(b): A safer Pimpl, using auto_ptr</span>
    <span style="color: #008000">//</span>

    <span style="color: #008000">// file c.h</span>
    <span style="color: #008000">//</span>
    <span style="color: #0000ff">class</span> C
    {
    <span style="color: #0000ff">public</span>:
      C();
      <span style="color: #008000">/*...*/</span>
    <span style="color: #0000ff">private</span>:
      <span style="color: #0000ff">class</span> CImpl; <span style="color: #008000">// forward declaration</span>
      auto_ptr&lt;CImpl&gt; pimpl_;
    };

    <span style="color: #008000">// file c.cpp</span>
    <span style="color: #008000">//</span>
    <span style="color: #0000ff">class</span> C::CImpl { <span style="color: #008000">/*...*/</span> };

    C::C() : pimpl_( <span style="color: #0000ff">new</span> CImpl ) { }</pre>
<p></p>
<p>现在，析构函数不需要担心删除pimpl_指针了，因为auto_ptr将自动处理它。事实上，如果没有其它需要显式写析构函数的原因，我们完全不需要自定义析构函数。显然，这比手动管理指针要容易得多，并且将对象所有权包含进对象是一个不错的习惯，这正是auto_ptr所擅长的。我们将在最后再次回顾这个例子。 </p>
<h3>所有权，源，以及调用者(Sinks)</h3>
<p>它本身很漂亮，并且做得非常好：从函数传入或传出<span style="font-family: 'Courier New'" class="Code">auto_ptr</span>s，是非常有用的，比如函数的参数或者返回值。</p>
<p>让我们看看为什么，首先我们考虑当拷贝auto_ptr的时候会发生什么：一个auto_ptr获得一个拥有指针的对象，并且在同一时间只允许有一个auto_ptr可以拥有这个对象。当你拷贝一个auto_ptr的时候，你自动将源auto_ptr的所有权，传递给目标auto_ptr；如果目标auto_ptr已经拥有了一个对象，这个对象将先被释放。在拷贝完之后，只有目标auto_ptr拥有指针，并且负责在合适的时间销毁它，而源将被设置为空（null），并且不能再被当作原有指针的代表来使用。 </p>
<p>例如：</p>
<p><pre class="gc-code">    <span style="color: #008000">// Example 5: Transferring ownership from</span>
    <span style="color: #008000">//            one auto_ptr to another</span>
    <span style="color: #008000">//</span>
    <span style="color: #0000ff">void</span> f()
    {
      auto_ptr&lt;T&gt; pt1( <span style="color: #0000ff">new</span> T );
      auto_ptr&lt;T&gt; pt2;

      pt1-&gt;DoSomething(); <span style="color: #008000">// OK</span>

      pt2 = pt1;  <span style="color: #008000">// now pt2 owns the pointer,</span>
                  <span style="color: #008000">// and pt1 does not</span>

      pt2-&gt;DoSomething(); <span style="color: #008000">// OK</span>

    } <span style="color: #008000">// as we go out of scope, pt2's destructor</span>
      <span style="color: #008000">// deletes the pointer, but pt1's does nothing</span></pre>
<p></p>
<p>但是要避免陷阱再次使用已经失去所有权的auto_ptr： </p>
<p><pre class="gc-code">    <span style="color: #008000">// Example 6: Never try to do work through</span>
    <span style="color: #008000">//            a non-owning auto_ptr</span>
    <span style="color: #008000">//</span>
    <span style="color: #0000ff">void</span> f()
    {
      auto_ptr&lt;T&gt; pt1( <span style="color: #0000ff">new</span> T );
      auto_ptr&lt;T&gt; pt2;

      pt2 = pt1;  <span style="color: #008000">// now pt2 owns the pointer, and</span>
                  <span style="color: #008000">// pt1 does not</span>

      pt1-&gt;DoSomething();
                  <span style="color: #008000">// error! following a null pointer</span>
    }</pre>
<p></p>
<p>谨记于心，我们现在看看auto_ptr如何在源和调用者之间工作。“源”这里是指一个函数，或者其它创建一个新资源的操作，并且通常将移交出资源的所有权。一个“调用者”函数反转这个关系，也就是获得已经存在对象的所有权（并且通常还负责释放它）。而不是有一个源和调用者，返回并且利用一个秃头指针（译者注：而不是使用一个局部变量来传递这个指针），虽然，通过一个秃头指针来获得一个资源通常很好： </p>
<p><pre class="gc-code">    <span style="color: #008000">// Example 7: Sources and sinks</span>
    <span style="color: #008000">//</span>

    <span style="color: #008000">// A creator function that builds a new</span>
    <span style="color: #008000">// resource and then hands off ownership.</span>
    <span style="color: #008000">//</span>
    auto_ptr&lt;T&gt; Source()
    {
      <span style="color: #0000ff">return</span> auto_ptr&lt;T&gt;( <span style="color: #0000ff">new</span> T );
    }

    <span style="color: #008000">// A disposal function that takes ownership</span>
    <span style="color: #008000">// of an existing resource and frees it.</span>
    <span style="color: #008000">//</span>
    <span style="color: #0000ff">void</span> Sink( auto_ptr&lt;T&gt; pt )
    {
    }

    <span style="color: #008000">// Sample code to exercise the above:</span>
    auto_ptr&lt;T&gt; pt( Source() ); <span style="color: #008000">// takes ownership</span></pre>
<p></p>
<p>注意下面的微妙的变化： </p>
<p>
<ol>
<li>
<p>Source()分配了一个新对象并且以一个完整安全的方式将它返回给调用者，并让调用者成为指针的拥有着。即使调用者忽略了返回值（显然，如果调用者忽略了返回值，你应该从来没有写过代码来删除这个对象，对吧？），分配的对象也将被自动安全地删除。</p>
<p>在本文的最后，我将演示返回一个auto_ptr是一个好习惯。让返回值包裹进一些东西比如auto_ptr通常是使得函数变得强健的有效方式。 </p>
<li>
<p>Sink()通过传值的方式获得对象所有权。当执行完Sink()的时候，当离开作用域的时候，删除操作将被执行（只要Sink()没有将所有权转移）。上面所写的Sink()函数实际上并没有对参数做任何事情，因此调用“Sink(pt);”就等于写了“pt.reset(0);”，但是大部分的Sink函数都将在释放它之前做一些工作。 </p></li></ol>
<p></p>
<h3>不可以做的事情，以及为什么不能做 </h3>
<p>谨记：千万不要以我之前没有提到的方式使用<span style="font-family: 'Courier New'" class="Code">auto_ptr</span>s。我已经看见过很多程序员试着用其他方式写<span style="font-family: 'Courier New'" class="Code">auto_ptr</span>s就像他们在使用其它对象一样。但问题是auto_ptr并不像其他对象。这里有些基本原则，我将把它们提出来以引起你的注意： </p>
<p><b>For </b><span class="Code"><b><span style="font-family: 'Courier New'">auto_ptr</span></b></span><b>, copies are NOT equivalent.<o:p> </o:p></b>（复制auto_ptr将与原来的不相等） </p>
<p>当你试着在一般的代码中使用<span style="font-family: 'Courier New'" class="Code">auto_ptr</span>s的时候，它将执行拷贝，并且没有任何提示，拷贝是不相等的（结果，它确实就是拷贝）。看下面这段代码，这是我在C++新闻组经常看见的： </p>
<p></p>
<p><pre class="gc-code">    <span style="color: #008000">// Example 8: Danger, Will Robinson!</span>
    <span style="color: #008000">//</span>
    vector&lt; auto_ptr&lt;T&gt; &gt; v;

    <span style="color: #008000">/* ... */</span>

    sort( v.begin(), v.end() );</pre>
<p></p>
<p></p>
<p>在标准容器中使用<span style="font-family: 'Courier New'" class="Code">auto_ptr</span>s<i>总是</i>不安全的。一些人可能要告诉你，他们的编译器或者类库能够很好地编译它们，而另一些人则告诉你在某一个流行的编译器的文档中看到这个例子，不要听他们的。 </p>
<p>问题是<span style="font-family: 'Courier New'" class="Code">auto_ptr</span>并不完全符合一个可以放进容器类型的前提，因为拷贝<span style="font-family: 'Courier New'" class="Code">auto_ptr</span>s是不等价的。首先，没有任何东西说明，vector不能决定增加并制造出“扩展”的内部拷贝。再次，当你调用一个一般函数的时候，它可能会拷贝元素，就像sort()那样，函数必须有能力假设拷贝是等价的。至少一个流行的排序拷贝“核心”的元素，如果你试着让它与<span style="font-family: 'Courier New'" class="Code">auto_ptr</span>s一起工作的话，它将拷贝一份“核心”的auto_ptr对象（因此转移所有权并且将所有权转移给一个临时对象），然后对其余的元素也采取相同的方式（从现有成员创建更多的拥有所有权的auto_ptr），当排序完成后，核心元素将被销毁，并且你将遇到一个问题：这组序列里至少一个auto_ptr（也就是刚才被掉包的那个核心元素）不再拥有对象所有权，而那个真实的指针已经随着临时对象的销毁而被删除了！ </p>
<p>于是标准委员会回退并希望做一些能够帮助你避免这些行为的事情：标准的auto_ptr被故意设计成当你希望在使用标准容器的时候使用它时打断你（或者，至少，在大部分的标准库实现中打断你）。为了达到这个目的，标准委员会利用这样一个技巧：让<span style="font-family: 'Courier New'" class="Code">auto_ptr</span>'s的拷贝构造函数和赋值操作符的右值（rhs）指向非常量。因为标准容器的单元素insert()函数，需要一个常量作为参数，因此<span style="font-family: 'Courier New'" class="Code">auto_ptr</span>s在这里就不工作了。（译者注：右值不能赋值给非常量） </p>
<h3>使用const auto_ptr是一个好习惯</h3>
<p>将一个auto_ptr设计成<span style="font-family: 'Courier New'" class="Code">const auto_ptr</span>s将不再丢失所有权：拷贝一个const auto_ptr是违法的（译者注：没有这样的构造函数），实际上你可以针对它做的唯一事情就是通过operator*()或者operator-&gt;()解引用它或者调用get()来获得所包含的指针的值。这意味着我们有一个简单明了的风格来表达一个绝不丢失所有权的auto_ptr： </p>
<p><pre class="gc-code">    <span style="color: #008000">// Example 9: The const auto_ptr idiom</span>
    <span style="color: #008000">//</span>
    <span style="color: #0000ff">const</span> auto_ptr&lt;T&gt; pt1( <span style="color: #0000ff">new</span> T );
        <span style="color: #008000">// making pt1 const guarantees that pt1 can</span>
        <span style="color: #008000">// never be copied to another auto_ptr, and</span>
        <span style="color: #008000">// so is guaranteed to never lose ownership</span>

    auto_ptr&lt;T&gt; pt2( pt1 ); <span style="color: #008000">// illegal</span>
    auto_ptr&lt;T&gt; pt3;
    pt3 = pt1;              <span style="color: #008000">// illegal</span>
    pt1.release();          <span style="color: #008000">// illegal</span>
    pt1.reset( <span style="color: #0000ff">new</span> T );     <span style="color: #008000">// illegal</span></pre>
<p></p>
<p>这就是我要说的cosnt！因此如果现在你要向世界证明你的auto_ptr是不会被改变并且将总是删除其所有权，加上const就是你要做的。const auto_ptr风格是有用的，你必须将它谨记于心。 </p>
<h3>auto_ptr以及异常安全</h3>
<p>最后，auto_ptr对写出异常安全的代码有时候非常必要，思考下面的代码：</p>
<p><pre class="gc-code">    <span style="color: #008000">// Example 10(a): Exception-safe?</span>
    <span style="color: #008000">//</span>
    String f()
    {
      String result;
      result = "<span style="color: #8b0000">some value</span>";
      cout &lt;&lt; "<span style="color: #8b0000">some output</span>";
      <span style="color: #0000ff">return</span> result;
    }</pre>
<p></p>
<p>该函数有两个可见的作用：它输出一些内容，并且返回一个String。关于异常安全的详细说明超出了本文的范围<sup><a href="#2">[2]</a></sup>，但是我们想要取得的目标就是强异常安全的保障，归结为确保函数的原子性——如果有异常，所有的作用一起发生或者都不发生。 </p>
<p>虽然在例10(a)中的代码非常精巧，看起来相当接近于异常安全的代码，但仍然有一些小的瑕疵，就像下面的客户代码所示： </p>
<p><pre class="gc-code">    String theName;
    theName = f();</pre>
<p></p>
<p>因为结果通过值返回，因此String的拷贝构造函数将被调用，而拷贝赋值操作符被调用来将结果拷贝到theName中。如果任何一个拷贝失败了，f()就完成了所有它的工作以及所有它的任务（这很好），但是结果是无法挽回的（哎哟我的妈呀） </p>
<p>我们可以做的更好吗，是否可以通过避免拷贝来避免这个问题？例如，我们可以 让函数有一个非常量引用参数并向下面这样返回值： </p>
<p><pre class="gc-code">    <span style="color: #008000">// Example 10(b): Better?</span>
    <span style="color: #008000">//</span>
    <span style="color: #0000ff">void</span> f( String&amp; result )
    {
      cout &lt;&lt; "<span style="color: #8b0000">some output</span>";
      result = "<span style="color: #8b0000">some value</span>";
    }</pre>
<p></p>
<p>这看起来很棒，但实际不是这样的，返回result的赋值的函数只完成了一个功能，而将其它事情留给了我们。它仍然会出错。因此这个做法不可取。 </p>
<p>解决这个问题的一个方法是返回一个指向动态分配指针的String对象，但是最好的解决方案是让我们做的更多，返回一个指针包含在auto_ptr： </p>
<p><pre class="gc-code">    <span style="color: #008000">// Example 10(c): Correct (finally!)</span>
    <span style="color: #008000">//</span>
    auto_ptr&lt;String&gt; f()
    {
      auto_ptr&lt;String&gt; result = <span style="color: #0000ff">new</span> String;
      *result = "<span style="color: #8b0000">some value</span>";
      cout &lt;&lt; "<span style="color: #8b0000">some output</span>";
      <span style="color: #0000ff">return</span> result;  <span style="color: #008000">// rely on transfer of ownership;</span>
                      <span style="color: #008000">// this can't throw</span>
    }</pre>
<p></p>
<p>这里是一个技巧，当我们有效隐藏所有的工作来构造第二个功能（返回值）当确保它可以被安全返回给调用者并且在第一个功能（打印消息）完成的时候没有抛出操作。我们知道一旦cout完成，返回值将成功交到调用者手中，并且无论如何都会正确清理：如果调用者接受返回值，调用者将得到这个拷贝的auto_ptr临时对象的所有权；如果调用者没有接受返回值，也就是忽略返回值，分配的String将在临时auto_ptr被销毁的时候自动清理。这种安全扩展的代价呢？就像我们经常实现的强异常安全一样，强安全通常消耗一些效率（通常比较小）——这里指额外的动态内存分配。但是当我们在效率和正确性之间做出选择的话，我们通常会选择后者！ </p>
<p>让我们养成在日常工作中使用auto_ptr的习惯。auto_ptr解决了常见的问题，并且能够使你的代码变得更安全和健壮，特别是它可以防止内存泄漏以及确保强安全。因为它是标准的，因此它在不同类库和平台之间是可移植的，因此无论你在哪里使用它，它都将是对的。 </p>
<h3>致谢</h3>
<p>This article is drawn from material in the new book Exceptional C++: 47 engineering puzzles, programming problems, and exception-safety solutions by Herb Sutter, © 2000 Addison Wesley Longman Inc., which contains further detailed treatments of points touched on briefly in this article, including exception safety, the Pimpl (compiler-firewall) Idiom, optimization, const-correctness, namespaces, and other C++ design and programming topics.</p>
<h3>注释</h3>
<ol>
<li>
<p><a name="1"></a>Pimpl风格可以有效减少项目构建时间，因为它在C私有部分改变的时候，阻止客户代码引起广泛的重新编译。更多关于Pimpl风格以及如何部署编译器墙，参考这本<a href="xc++.htm">Exceptional C++</a></i>的条款26到30。（Addison-Wesley, 2000） </p>
<li>
<p><a name="2"></a>See the article <span><a href="http://www.informit.com/content/downloads/aw/meyerscddemo/DEMO/MAGAZINE/SU_FRAME.HTM">"Exception-Safe Generic Containers"</a></span> originally published in <em>C++ Report</em> and available on the <i>Effective C++ CD</i> (Scott Meyers, Addison-Wesley, 1999) and Items 8 to 19 in <i><a href="xc++.htm">Exceptional C++</a></i> (Herb Sutter, Addison-Wesley, 2000).</p></li></ol><img src ="http://www.cppblog.com/mymsdn/aggbug/111882.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2010-04-07 19:08 <a href="http://www.cppblog.com/mymsdn/archive/2010/04/07/Using-auto_ptr-Effectively.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]从C++的Return Value Optimization (RVO)到C#的value type</title><link>http://www.cppblog.com/mymsdn/archive/2010/04/06/111777.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Tue, 06 Apr 2010 11:42:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2010/04/06/111777.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/111777.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2010/04/06/111777.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/111777.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/111777.html</trackback:ping><description><![CDATA[<p>先看一段简单的C++代码： <pre class="gc-code">Type get(<span style="color: #0000ff">int</span> I){
    <span style="color: #0000ff">return</span> Type(i);
} 

Type t = get(1); </pre>
<p>这里， 我们从C++的基本语义看上去， 应该是Type(i) 调用一次拷贝构造函数， 在堆栈中生成一个临时对象；然后，用该对象构造返回对象；然后对这个临时对象调用析构函数；在调用者方， 用返回的临时对象调用拷贝构造函数以初始化对象t, 返回对象的析构函数在这之后， 函数返回之前调用。 
<p>所以， Type t = get(i); 应该有三个拷贝构造函数和两个析构函数的调用. 
<p>可是， 还有一种说法是， 编译器可能会对这两个临时对象进行优化，最终的优化结果会是只有一次的构造函数。因为很明显地可以看到， 这里我们其实只是要用一个整数构造一个Type对象。 
<p>嗯. 似乎很有道理！ 
<p>那么， 哪一种说法对呢？ 没有调查就没有发言权，于是本人用VC++6.0做了实验。 放了些cout&lt;&lt;…..在拷贝构造函数里，观察打印的结果， 结果却是跟我的simple, naïve的预测一致。三个拷贝构造函数， 两个析构函数。 
<p>“你个弱智编译器！脑袋进水了吧？”(忘了编译器没脑袋了)“很明显在这个例子里我的两个临时对象都没有用的啊！” 
<p>于是，上网， 查资料， google一下吧！ 
<p>下面是我查到的一些结果： 
<p>其实， 这种对值传递的优化的研究， 并不只局限于返回值。对下面这个例子： <pre class="gc-code"><span style="color: #0000ff">void</span> f(T t) { } 
<span style="color: #0000ff">void</span> main(<span style="color: #0000ff">void</span>){ 
    T t1;
    f(t1); 
} </pre>
<p>也有这种考虑。 
<p>f(T)是按值传递的。语义上应该做一个复制， 使得函数内部对T的改变不会影响到原来的t1. 
<p>但是，因为在调用f(t1)之后， 我们没有再使用t1(除了一个隐含的destructor调用)，是否可能把复制优化掉， 直接使用t1呢？这样可以节省掉一个拷贝构造函数和一个析构函数。 
<p>可是， 不论是对返回值的优化， 还是对上面这种局部对象的优化，在1995年的C++新标准草案出台前都是为标准所严格限制的 (虽然有些编译器并没有遵行这个标准， 还是支持了这种“优化”) 
<p>那么， 这又是为什么呢？ 
<p>这里面涉及到一个普遍的对side-effect的担忧。 
<p>什么又是side-effect呢？ 
<p>所谓side-effect就是一个函数的调用与否能够对系统的状态造成区别。 
<p>int add(int i, int j){ return i+j; }就是没有side-effect的，而 
<p>void set(int* p, int I, int v){ p[I]=v; }就是有side-effect的。因为它改变了一个数组元素的值， 而这个数组元素在函数外是可见的。 
<p>通常意义上来说， 所有的优化应该在不影响程序的可观察行为的基础上进行的。否则，快则快了， 结果却和所想要的完全不同！ 
<p>而C++的拷贝构造函数和析构函数又很多都是有side-effect的。如果我们的“优化”去掉了一个有side-effect的拷贝构造函数和一个析构函数， 这个“优化”就有可能改变程序的可观察行为。（注意， 我这里说的是“可能”，因为“负负得正”， 两个有side-effect的函数的调用， 在不考虑并行运行的情况下， 也许反而不会影响程序的可观察行为。不过， 这种塞翁失马的事儿， 编译器就很难判断了） 
<p>基于这种忧虑, 1995年以前的标准， 明确禁止对含有side-effect的拷贝构造函数和析构函数的优化。同时， 还有一些对C++扩充的提议， 考虑让程序员自己对类进行允许优化的声明。 程序员可以明确地告诉编译器：不错， 我这个拷贝构造函数， 析构函数是有side-effect, 但你别管， 尽管优化， 出了事有我呢！ 
<p>哎， side-effect真是一个让人又恨又爱的东西！它使编译器的优化变得困难；加大了程序维护和调试的难度。因此 functional language 把side-effect当作洪水猛兽一样，干脆禁止。但同时，我们又很难离开side-effect. 不说程序员们更习惯于imperative 的编程方法, 象数据库操作，IO操作都天然就是side-effect. 
<p>不过，个人还是认为C++标准对“优化”的保守态度是有道理的。无论如何，让“优化”可以潜在地偷偷地改变程序的行为总是让人想起来就不舒服的。 
<p>但是， 矛盾是对立统一的。（想当年俺马列可得了八十多分呢）。 对这种aggressive的“优化”的呼声是一浪高过一浪。 以Stan Lippeman为首的一小撮顽固分子对标准的颠覆和和平演变的阴谋从来就没有停止过。 这不？在1996年的一个风雨交加的夜晚， 一个阴险的C++新标准草案出炉了。在这个草案里， 加入了一个名为RVO (Return Value Optimization) 的放宽对优化的限制， 妄图走资本主义道路， 给资本家张目的提案。其具体内容就是说：允许编译器对命名过的局部对象的返回进行优化， 即使拷贝构造函数/析构函数有side-effect也在所不惜。这个提议背后所隐藏的思想就是：为了提高效率， 宁可冒改变程序行为的风险。宁要资本主义的苗， 不要社会主义的草了！ 
<p>我想， 这样的一个罪大恶极的提案竟会被提交，应该是因为C++的值拷贝的语义的效率实在太“妈妈的”了。 当你写一个 Complex operator+(const Complex&amp; c1, const Complex&amp; c2);的时候， 竟需要调用好几次拷贝构造函数和析构函数！同志们！（沉痛地， 语重心长地）社会主义的生产关系的优越性怎么体现啊？ 
<p>接下来， 当我想Google C++最新的标准， 看RVO是否被最终采纳时， 却什么也找不到了。 到ANSI的网站上去， 居然要付钱才能DOWNLOAD文档。 “老子在城里下馆子都不付钱， down你几个烂文档还要给钱？！” 
<p>故事没有结局， 实在是不爽。 也不知是不是因为标准还没有敲定， 所以VC++6 就没有优化， 还是VC根本就没完全遵守标准。 
<p>不过，有一点是肯定的。 当写程序的时候， 最好不要依赖于RVO (有人， 象Stan Lippeman, 又叫它NRV优化)。 因为， 不论对标准的争论是否已经有了结果， 实际上各个编译器的实现仍还是各自为政， 没有统一。 一个叫SCOtt Meyers的家伙(忘了是卖什么的了)就说， 如果你的程序依赖于RVO, 最好去掉这种依赖。也就是说， 不管RVO到底标准不标准， 你还是不能用。 不仅不能用， 还得时刻警惕着RVO可能带来的程序行为上的变化。 （也不知这帮家伙瞎忙了半天到底为啥！） 
<p>说到这里， 倒想起了C#里一个困惑了我很久的问题。记得读C#的specification的时候， 非常不解为什么C#不允许给value type 定义析构函数。 
<p>这里， 先简略介绍一下C#里的value type (原始数据类型， struct 类型)。 
<p>在C#里的value_type就象是值， 永远只能copy, 取值。因此， 它永远是in-place的。如果你把一个value type的数据放在一个对象里，它的生命期就和那个对象相同；如果你声明一个value type 的变量在函数中， 它的生命期就在lexical scope里。 
<p>{ 
<p>&nbsp; The_ValueType value; 
<p>}//value 到这里就死菜了 
<p>啊呀呀！ 这不正是我们怀念的C++的stack object吗？ 
<p>在C++里，Auto_ptr, shared_ptr, 容器们， 不都是利用析构函数来管理资源的吗？ 
<p>C#，Java 虽然利用garbage collection技术来收集无用对象， 使我们不用再担心内存的回收。 但garbage collection并不保证无用对象一定被收集， 并不保证Dispose()函数一定被调用， 更不保证一个对象什么时候被回收。 所以对一些非内存的资源， 象数据库连接， 网络连接， 我们还是希望能有一个类似于smart pointer的东西来帮我们管理啊。（try-finally 虽然可以用， 但因为它影响到lexical scope, 有时用起来不那么方便） 
<p>于是， 我对C#的取消value type的析构函数充满了深厚的阶级仇恨。 
<p>不过， 现在想来， C#的这种设计一定是惩于C++失败的教训： 
<p>&nbsp;&nbsp; 1. value type 没有拷贝构造函数。C#只做缺省copy, 没有side-effect<br>&nbsp;&nbsp; 2. value type 不准有析构函数。C#有garbage collection, 析构函数的唯一用途只会是做一些side-effect象关闭数据库连接。 所以取消了析构函数， 就取消了value type的side-effect.<br>&nbsp;&nbsp; 3. 没有了side-effect, 系统可以任意地做优化了 
<p>对以下程序： 
<p>The_Valuetype get(int I){return The_Valuetype(i);} 
<p>The_Valuetype t = get(1); 
<p>在C#里我们可以快乐地说：只调用了一次构造函数。 再没有side-effect的沙漠， 再没有难以优化的荒原， smart pointer望而却步， 效率之花处处开遍。 I have a dream, ……</p>
<p>转载自：<a title="http://gugu99.itpub.net/post/34143/466008" href="http://gugu99.itpub.net/post/34143/466008">http://gugu99.itpub.net/post/34143/466008</a></p><img src ="http://www.cppblog.com/mymsdn/aggbug/111777.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2010-04-06 19:42 <a href="http://www.cppblog.com/mymsdn/archive/2010/04/06/111777.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>模板类型推断的一个小问题</title><link>http://www.cppblog.com/mymsdn/archive/2010/04/05/111629.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Sun, 04 Apr 2010 16:28:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2010/04/05/111629.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/111629.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2010/04/05/111629.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/111629.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/111629.html</trackback:ping><description><![CDATA[<pre class="gc-code"><span style="color: green">/*
 * type_infer_in_const_char_array.cpp
 *
 *  Created on: 2010-4-4
 *      Author: volnet
 *      Ref: http://topic.csdn.net/u/20100403/16/aebc3e87-ae49-4a18-ba0b-263348b512e3.html
 *      ShortRef: http://is.gd/be914
 */

</span><span style="color: blue">#include </span><span style="color: #a31515">&lt;stdlib.h&gt;
</span><span style="color: blue">#include </span><span style="color: #a31515">&lt;iostream&gt;
</span><span style="color: blue">#ifdef </span>_MSC_VER
<span style="color: blue">#include </span><span style="color: #a31515">&lt;typeinfo.h&gt;
</span><span style="color: blue">#else
</span><span style="color: gray">#include &lt;typeinfo&gt;
</span><span style="color: blue">#endif

template </span>&lt;<span style="color: blue">typename </span>T&gt;
<span style="color: blue">int </span>compare(<span style="color: blue">const </span>T &amp;v1, <span style="color: blue">const </span>T &amp;v2) {
    std::cout &lt;&lt; <span style="color: #a31515">"invoking compare ..." </span>&lt;&lt; std::endl;
    <span style="color: blue">if</span>(v1&lt;v2) <span style="color: blue">return </span>-1;
    <span style="color: blue">if</span>(v2&lt;v1) <span style="color: blue">return </span>1;
    <span style="color: blue">return </span>0;
}
<span style="color: blue">int </span>main()
{
    <span style="color: green">//error:
    // no matching function for call to `compare(const char[3], const char[6])'
    // compare("hi","world");
    </span>compare&lt;<span style="color: blue">const char</span>*&gt;(<span style="color: #a31515">"hi"</span>,<span style="color: #a31515">"world"</span>);
    <span style="color: green">//what's the real type about "abcd"?
    // const char * or const char [n] ?
    </span>std::cout &lt;&lt; <span style="color: blue">typeid</span>(<span style="color: #a31515">"hi"</span>).name() &lt;&lt; std::endl;        <span style="color: green">// char const [3]
    </span>std::cout &lt;&lt; <span style="color: blue">typeid</span>(<span style="color: #a31515">"world"</span>).name() &lt;&lt; std::endl;    <span style="color: green">// char const [6]
    </span>std::cout &lt;&lt; <span style="color: blue">typeid</span>(<span style="color: #a31515">"dlrow"</span>).name() &lt;&lt; std::endl;    <span style="color: green">// char const [6]
    // the compiler infer the typename T is char const [6]
    </span>compare(<span style="color: #a31515">"world"</span>, <span style="color: #a31515">"dlrow"</span>);
}


</pre><img src ="http://www.cppblog.com/mymsdn/aggbug/111629.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2010-04-05 00:28 <a href="http://www.cppblog.com/mymsdn/archive/2010/04/05/111629.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>智能指针的实现（1）</title><link>http://www.cppblog.com/mymsdn/archive/2010/04/04/design_of_smart_ptr_1.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Sun, 04 Apr 2010 15:08:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2010/04/04/design_of_smart_ptr_1.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/111621.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2010/04/04/design_of_smart_ptr_1.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/111621.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/111621.html</trackback:ping><description><![CDATA[<p>首先我们面临的挑战是，声明堆中的数据需要我们用new关键字，直到我们显示调用了delete之后，它们才会被移除，但问题是，我们什么时候应该移除？如果调用语句在上下行中，我们自然知道如何移除。我们知道如果对象声明在堆中，那么在它离开它的作用域中的时候，可以自动释放，如果我们能够用栈对象来管理堆对象，在栈对象自动释放的时候，释放堆对象，就不需要显式调用delete语句了：  <p>于是就有了下面的做法，应该不难理解：<pre class="gc-code"><span style="color: blue">template</span>&lt;<span style="color: blue">class </span>T&gt;
<span style="color: blue">class </span>smart_ptr {
<span style="color: blue">public</span>:
    smart_ptr(T* t = 0) { real_ptr = t; }
    ~smart_ptr() { <span style="color: blue">delete </span>real_ptr; }
    T* <span style="color: blue">operator </span>-&gt;() <span style="color: blue">const </span>{ <span style="color: blue">return </span>real_ptr; }
    T&amp; <span style="color: blue">operator </span>*() <span style="color: blue">const </span>{ <span style="color: blue">return </span>*real_ptr; }
<span style="color: blue">private</span>:
    T* real_ptr;
};</pre>
<p>我们希望我们的智能指针能够像指针一样地工作，但下面的工作方式似乎存在问题： 
<p>在普通的dumb指针中，以下行为是正确的：<pre class="gc-code"><span style="color: blue">void </span>letUsGo(BaseClass* objPtr);

DerivedClass* derivedObjPtr2 = <span style="color: blue">new </span>DerivedClass();
letUsGo(derivedObjPtr2);
<span style="color: blue">delete </span>derivedObjPtr2;</pre>
<p>但是，以下代码呢？<pre class="gc-code"><span style="color: blue">void </span>letUsSmartGo(<span style="color: blue">const </span>smart_ptr&lt;BaseClass&gt;&amp; objPtr);
smart_ptr&lt;DerivedClass&gt; smartDerivedObjPtr2(<span style="color: blue">new </span>DerivedClass());
<span style="color: green">// the smart_ptr&lt;DerivedClass&gt; is not inherited from the smart_ptr&lt;BaseClass&gt;
// the compiler can't find the class to cast it, so it must cause the error.
</span>letUsSmartGo(smartDerivedObjPtr2);</pre><a href="http://11011.net/software/vspaste"></a>
<p>下面的过程描述了这个变化所需要的一些支持： 
<p>1、error C2664: “letUsSmartGo”: 不能将参数 1 从“smart_ptr&lt;T&gt;”转换为“const smart_ptr&lt;T&gt; &amp;”<br>2、smartDerivedObjPtr2的类型：<br>&nbsp;&nbsp;&nbsp; smart_ptr&lt;DerivedClass&gt; smartDerivedObjPtr2(new DerivedClass());<br>3、letUsSmartGo的声明：<br>&nbsp;&nbsp;&nbsp; void letUsSmartGo(const smart_ptr&lt;BaseClass&gt;&amp;);<br>4、问题转化为，如何从smart_ptr&lt;DerivedClass&gt;到const smart_ptr&lt;BaseClass&gt;&amp;的转变。<br>5、针对letUsSmartGo的声明，可以有的实参类型包括：<br>&nbsp;&nbsp;&nbsp; const smart_ptr&lt;BaseClass&gt;<br>&nbsp;&nbsp;&nbsp; smart_ptr&lt;BaseClass&gt;<br>&nbsp;&nbsp;&nbsp; 假设存在以下类型 smart_derived_ptr : smart_ptr&lt;BaseClass&gt;，那么smart_derived_ptr也是可以被传递的。<br>6、这里存在这样一个问题：<br>&nbsp;&nbsp;&nbsp; new DerivedClass() 被传递给smartDerivedObjPtr2之后，smartDerivedObjPtr2就拥有了它的指针。如果从smartDerivedObjPtr2隐式转换成另一个smart_ptr&lt;X&gt;后，我们需要解决的就是将smartDerivedObjPtr2所拥有的指针传递给smart_ptr&lt;X&gt;并将smartDerivedObjPtr2的内部指针清零（这样就不会在smartDerivedObjPtr2被销毁的时候，因为调用delete real_ptr，而它的新拷贝在离开作用域的时候，一样会再次调用delete real_ptr，而此时real_ptr指向的对象已经被释放，因此这样的行为是未定义的。）<br>7、因此，定义如下方法即可：<pre class="gc-code"><span style="color: blue">template</span>&lt;<span style="color: blue">class </span>T&gt; 
<span style="color: blue">class </span>smart_ptr { 
<span style="color: blue">public</span>:
    smart_ptr(T* t = 0) { 
        std::cout &lt;&lt; <span style="color: #a31515">"creating smart_ptr ...smart_ptr(T* t = 0)" </span>&lt;&lt; std::endl;
        real_ptr = t; 
    } 

<strong>    <span style="color: blue">template</span>&lt;<span style="color: blue">class </span>U&gt;
    smart_ptr(smart_ptr&lt;U&gt;&amp; rhs) : real_ptr(rhs.real_ptr){
        std::cout &lt;&lt; <span style="color: #a31515">"creating smart_ptr ...smart_ptr(smart_ptr&lt;U&gt;&amp; rhs)" </span>&lt;&lt; std::endl;
        rhs.real_ptr = 0;
    }</strong>

    ~smart_ptr() { 
        std::cout &lt;&lt; <span style="color: #a31515">"destoring smart_ptr ..." </span>&lt;&lt; std::endl;
        <span style="color: blue">delete </span>real_ptr; 
    } 

    T* <span style="color: blue">operator </span>-&gt;() <span style="color: blue">const </span>{ <span style="color: blue">return </span>real_ptr; } 
    T&amp; <span style="color: blue">operator </span>*() <span style="color: blue">const </span>{ <span style="color: blue">return </span>*real_ptr; } 
<span style="color: green"> 
    </span>T* real_ptr; 
};</pre>
<p>8、但是这里real_ptr按照习惯应该是一个私有成员，而且我们在完成该方法时候，希望能够实现一种所谓的所有权转移，也就是将内部的指针传递给另一个智能指针，而这应该是一个原子过程。因此，我们实现以下方法：</p><pre class="gc-code"><span style="color: blue">template</span>&lt;<span style="color: blue">class </span>T&gt; 
<span style="color: blue">class </span>smart_ptr { 
<span style="color: blue">public</span>:
    smart_ptr(T* t = 0) { 
        std::cout &lt;&lt; <span style="color: #a31515">"creating smart_ptr ...smart_ptr(T* t = 0)" </span>&lt;&lt; std::endl;
        real_ptr = t; 
    } 

    <span style="color: blue">template</span>&lt;<span style="color: blue">class </span>U&gt;
    smart_ptr(smart_ptr&lt;U&gt;&amp; rhs) : real_ptr(rhs.release()){
        std::cout &lt;&lt; <span style="color: #a31515">"creating smart_ptr ...smart_ptr(smart_ptr&lt;U&gt;&amp; rhs)" </span>&lt;&lt; std::endl;
    }

    ~smart_ptr() { 
        std::cout &lt;&lt; <span style="color: #a31515">"destoring smart_ptr ..." </span>&lt;&lt; std::endl;
        <span style="color: blue">delete </span>real_ptr; 
    }

    T* <span style="color: blue">operator </span>-&gt;() <span style="color: blue">const </span>{ <span style="color: blue">return </span>real_ptr; } 
    T&amp; <span style="color: blue">operator </span>*() <span style="color: blue">const </span>{ <span style="color: blue">return </span>*real_ptr; } 

    <span style="color: green">// helper
    </span>T* release() {
        T* tmp = real_ptr;
        real_ptr = 0;
        <span style="color: blue">return </span>tmp;
    }
<span style="color: blue">private</span>: 
    T* real_ptr; 
};</pre><img src ="http://www.cppblog.com/mymsdn/aggbug/111621.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2010-04-04 23:08 <a href="http://www.cppblog.com/mymsdn/archive/2010/04/04/design_of_smart_ptr_1.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用事实说话，C++ Profiler（Visual Studio 2008）</title><link>http://www.cppblog.com/mymsdn/archive/2010/04/01/111307.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Thu, 01 Apr 2010 10:02:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2010/04/01/111307.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/111307.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2010/04/01/111307.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/111307.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/111307.html</trackback:ping><description><![CDATA[<p><a href="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/CProfilerVisualStudio2008_FD62/image_2.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/CProfilerVisualStudio2008_FD62/image_thumb.png" width="1186" height="786"></a> </p> <p>1、设置“生成时启用C/C++代码分析”为“是”，如果不设置此项，程序速度将出乎你的意料……</p> <p><a href="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/CProfilerVisualStudio2008_FD62/image_4.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/CProfilerVisualStudio2008_FD62/image_thumb_1.png" width="852" height="640"></a> </p> <p>2、点击“分析”-&gt;“启动性能向导”</p> <p><a href="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/CProfilerVisualStudio2008_FD62/image_6.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/CProfilerVisualStudio2008_FD62/image_thumb_2.png" width="890" height="370"></a> </p> <p>3、在“性能资源管理器”中右键新建的性能报告节点，右键“启动并启用分析功能”。</p> <p><a href="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/CProfilerVisualStudio2008_FD62/image_10.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/CProfilerVisualStudio2008_FD62/image_thumb_4.png" width="658" height="262"></a> </p> <p>虽然此处有“启用分析功能”，但如果在配置里面没有进行设置，第一次的测试报告结果将是不准确的。</p> <p>4、选择两个性能报告（ctrl+鼠标），右键“比较性能报告”。</p> <p><a href="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/CProfilerVisualStudio2008_FD62/image_8.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/CProfilerVisualStudio2008_FD62/image_thumb_3.png" width="785" height="370"></a> </p> <p></p> <p></p> <p>用性能报告将有助于提高程序的性能，并且快速定位问题所在，剩下的结果就是你自己需要多观察，分析性能报告所反映的问题了。<br></p> <p>更多</p> <p>VC++ 6.0详见这里&gt;&gt; <a title="http://neural.cs.nthu.edu.tw/jang/mir/technicalDocument/vc6_profile/index.htm" href="http://neural.cs.nthu.edu.tw/jang/mir/technicalDocument/vc6_profile/index.htm">http://neural.cs.nthu.edu.tw/jang/mir/technicalDocument/vc6_profile/index.htm</a></p> <p>第三方工具&gt;&gt; <a title="http://www.semdesigns.com/Products/Profilers/CppProfiler.html" href="http://www.semdesigns.com/Products/Profilers/CppProfiler.html">http://www.semdesigns.com/Products/Profilers/CppProfiler.html</a></p><img src ="http://www.cppblog.com/mymsdn/aggbug/111307.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2010-04-01 18:02 <a href="http://www.cppblog.com/mymsdn/archive/2010/04/01/111307.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ubuntu下编译boost（附Eclipse静态链接库设置）</title><link>http://www.cppblog.com/mymsdn/archive/2010/03/30/install-boost-under-boost.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Tue, 30 Mar 2010 09:17:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2010/03/30/install-boost-under-boost.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/111019.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2010/03/30/install-boost-under-boost.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/111019.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/111019.html</trackback:ping><description><![CDATA[这不是一篇向导，全面的向导请看<a href="http://www.boost.org/doc/libs/1_42_0/more/getting_started/unix- variants.html">这里</a>（http://goo.gl/XcAf）。<br>这仅是一篇笔记。这里用<a href="http://www.boost.org/doc/libs/1_42_0/more/getting_started/unix- variants.html#easy-build-and-install">bjam方式</a>进行编译。<br><ol><li>下载boost。（http://cdnetworks-kr-1.dl.sourceforge.net/project/boost/boost/1.42.0/boost_1_42_0.tar.bz2）</li><li>解压到指定文件夹，我是将它解压到根目录下的一个sourcecode文件夹下。<div class="console">&#160;&#160; &#160;/home/volnet/sourcecode/boost_1_42_0</div></li><li>启动终端（ctrl+f2,输入&#8220;gnome-terminal&#8221;）。生成bjam脚本。<div class="console">&#160;&#160; &#160;./bootstrap.sh --prefix=/home/volnet/sourcecode/boost_install</div>如果不带--prefix参数的话（<b>推荐</b>），默认的路径是/usr/local/include和/usr/local/lib<div class="console">&#160;&#160; &#160;./bootstrap.sh</div>使用--help参数可以查看帮助，用-h可以查看简要帮助。<div class="console">&#160;&#160; &#160;./bootstrap.sh --help</div>生成脚本bjam，已经存在的脚本将被自动备份。<pre class="console">volnet@Ubuntu:~/sourcecode/boost_1_42_0$ ./bootstrap.sh --prefix=/home/volnet/sourcecode/boost_install/<br>Building Boost.Jam with toolset gcc... tools/jam/src/bin.linuxx86/bjam<br>Detecting Python version... 2.6<br>Detecting Python root... /usr<br>Unicode/ICU support for Boost.Regex?... /usr<br>Backing up existing Boost.Build configuration in project-config.jam.4<br>Generating Boost.Build configuration in project-config.jam...<br><br>Bootstrapping is done. To build, run:<br><br>&#160;&#160;&#160; ./bjam<br>&#160;&#160;&#160; <br>To adjust configuration, edit 'project-config.jam'.<br>Further information:<br><br>&#160;&#160; - Command line help:<br>&#160;&#160;&#160;&#160; ./bjam --help<br>&#160;&#160;&#160;&#160; <br>&#160;&#160; - Getting started guide: <br>&#160;&#160;&#160;&#160; http://www.boost.org/more/getting_started/unix-variants.html<br>&#160;&#160;&#160;&#160; <br>&#160;&#160; - Boost.Build documentation:<br>&#160;&#160;&#160;&#160; http://www.boost.org/boost-build2/doc/html/index.html<br><br></pre></li><li>然后就是利用生成的bjam脚本编译源码了。<br><div class="console">volnet@Ubuntu:~/sourcecode/boost_1_42_0$ sudo ./bjam -a -sHAVE_ICU=1 installNote: Building Boost.Regex with Unicode/ICU support enabled&#160;&#160;&#160; Using ICU in&#160; /usr/include</div><ul><li>./是unix-like系统执行文件的前缀，这里就是指要执行bjam文件。</li><li>-a是参数，代表重新编译（Rebuild）。输入./bjam -h获得更多帮助。</li><li>-sHAVE_ICU=1，代表支持Unicode/ICU。<a href="http://en.wikipedia.org/wiki/International_Components_for_Unicode">点击这里（http://goo.gl/ySEe）</a><br><div class="note">前提：系统内需要安装有libicu-dev，可以在终端输入：<br><div class="console">sudo apt-get install libicu-dev</div></div></li><li>install，表示安装</li><li>--clean，表示清理。当前语句中包含-a，则不需要先手动清理，否则需要先运行<div class="console">./bjam --clean</div></li></ul></li><li>如果你执行上一步，会出现诸如：mpi的问题，多半是本机没有安装mpi。根据系统提示，你可以找到有/home/volnet/sourcecode/boost_1_42_0/tools/build/v2/user-config.jam。在文件最后跟上<div class="console">using mpi ;</div>即可。然后如果还是有mpi问题，说明本机没有安装mpi。<div class="console">sudo apt-get install mpi-default-dev</div></li></ol><br>界此应该顺利通过编译了。并在/usr/local/lib下有了boost的库了。<br>下面讨论一下链接静态链接库在Eclipse里的问题。<br>在<a href="http://www.boost.org/doc/libs/1_42_0/more/getting_started/unix-variants.html#link-your-program-to-a-boost-library">Unix variants</a>向导里，官方提供了一个使用正则表达式的程序。<br>在Eclipse里，新增c++ project，并使用Linux C++编译器。将代码拷贝到文件中：<br>因为要静态链接到正则表达式的库，所以如下图所示，设置对应的*.a文件路径到eclipse，以使链接器能够找到它。<br><img src="http://www.cppblog.com/images/cppblog_com/mymsdn/static-library-in-eclipse.png" border="0"><br><br>编译通过！<br>为了我们的程序能够正确载入，我们需要让我们的程序在我们的系统范围内也能够找到我们的库。这时候我们需要在设置一下。详见<a href="http://www.boost.org/doc/libs/1_42_0/more/getting_started/unix-variants.html#test-your-program">这部分</a>的相关介绍。<br>测试程序！<br><div class="console">volnet@Ubuntu:~/workspace/boost_get_started/Debug$ ./boost_get_started &lt test<br>Will Success Spoil Rock Hunter?<br></div>这里test是一个文件。<br><br><br> <img src ="http://www.cppblog.com/mymsdn/aggbug/111019.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2010-03-30 17:17 <a href="http://www.cppblog.com/mymsdn/archive/2010/03/30/install-boost-under-boost.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>单参数构造函数的问题，single-argument construct</title><link>http://www.cppblog.com/mymsdn/archive/2010/03/29/single-argument-construct.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Mon, 29 Mar 2010 07:37:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2010/03/29/single-argument-construct.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/110879.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2010/03/29/single-argument-construct.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/110879.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/110879.html</trackback:ping><description><![CDATA[<p>关于单一参数构造函数的问题，主要是因为单一参数被编译器用作隐式类型转换，从而导致一些不可预期的事件的发生，请参见代码详细注释：</p><pre class="gc-code"><span style="color: green">/*
 * single_argument_ctor.cpp
 *
 *  Created on: 2010-3-29
 *      Author: Volnet
 *      Compiler: GNU C++(version 3.4.5)
 *                MSVC CL(version 15.00.30729.01)
 */

</span><span style="color: blue">#include </span><span style="color: #a31515">&lt;stdlib.h&gt;
</span><span style="color: blue">#include </span><span style="color: #a31515">&lt;iostream&gt;
</span><span style="color: blue">#include </span><span style="color: #a31515">&lt;sstream&gt;

</span><span style="color: green">// single-argument class
</span><span style="color: blue">class </span>SingleArgumentClass {
<span style="color: blue">private</span>:
    <span style="color: blue">int </span>_inner;
<span style="color: blue">public</span>:
    SingleArgumentClass()
        :_inner(-1)
    {

    }
    SingleArgumentClass(<span style="color: blue">int </span>actual)
        :_inner(actual)
    {

    }
    <span style="color: blue">bool operator</span>==(<span style="color: blue">const </span>SingleArgumentClass&amp; rhs);
    std::string str(){
        <span style="color: green">// we'd better to use boost::lexical_cast to cast.
        // #region cast
        </span>std::stringstream strStream;
        strStream &lt;&lt; _inner;
        std::string str;
        strStream &gt;&gt; str;
        <span style="color: green">// #endregion
        </span><span style="color: blue">return </span>str;
    }
};
<span style="color: blue">bool
</span>SingleArgumentClass::<span style="color: blue">operator </span>==(<span style="color: blue">const </span>SingleArgumentClass&amp; rhs){
    <span style="color: blue">if</span>(_inner == rhs._inner)
        <span style="color: blue">return true</span>;
    <span style="color: blue">return false</span>;
}

<span style="color: green">// single-argument class fixed bug by explicit keyword.
</span><span style="color: blue">class </span>SingleArgumentClassFixedBugByExplicitKeyword {
<span style="color: blue">private</span>:
    <span style="color: blue">int </span>_inner;
<span style="color: blue">public</span>:
    SingleArgumentClassFixedBugByExplicitKeyword()
        :_inner(-1)
    {

    }
    <span style="color: blue">explicit </span>SingleArgumentClassFixedBugByExplicitKeyword(<span style="color: blue">int </span>actual)
        :_inner(actual)
    {

    }
    <span style="color: blue">bool operator</span>==(<span style="color: blue">const </span>SingleArgumentClassFixedBugByExplicitKeyword&amp; rhs);
    std::string str(){
        <span style="color: green">// we'd better to use boost::lexical_cast to cast.
        // #region cast
        </span>std::stringstream strStream;
        strStream &lt;&lt; _inner;
        std::string str;
        strStream &gt;&gt; str;
        <span style="color: green">// #endregion
        </span><span style="color: blue">return </span>str;
    }
};
<span style="color: blue">bool
</span>SingleArgumentClassFixedBugByExplicitKeyword::<span style="color: blue">operator </span>==(<span style="color: blue">const </span>SingleArgumentClassFixedBugByExplicitKeyword&amp; rhs){
    <span style="color: blue">if</span>(_inner == rhs._inner)
        <span style="color: blue">return true</span>;
    <span style="color: blue">return false</span>;
}

<span style="color: green">// single-argument class fixed bug by helper class.
</span><span style="color: blue">class </span>ActualType {
<span style="color: blue">public</span>:
    ActualType(<span style="color: blue">int </span>value):_value(value){};
    <span style="color: blue">int </span>get_value(){ <span style="color: blue">return </span>_value; }
<span style="color: blue">private</span>:
    <span style="color: blue">int </span>_value;
};
<span style="color: blue">class </span>SingleArgumentClassFixedBugByHelperClass {
<span style="color: blue">private</span>:
    <span style="color: blue">int </span>_inner;
<span style="color: blue">public</span>:
    SingleArgumentClassFixedBugByHelperClass()
        :_inner(-1)
    {

    }
    SingleArgumentClassFixedBugByHelperClass(ActualType actual)
        :_inner(actual.get_value())
    {

    }
    <span style="color: blue">bool operator</span>==(<span style="color: blue">const </span>SingleArgumentClassFixedBugByHelperClass&amp; rhs);
    std::string str(){
        <span style="color: green">// we'd better to use boost::lexical_cast to cast.
        // #region cast
        </span>std::stringstream strStream;
        strStream &lt;&lt; _inner;
        std::string str;
        strStream &gt;&gt; str;
        <span style="color: green">// #endregion
        </span><span style="color: blue">return </span>str;
    }
};
<span style="color: blue">bool
</span>SingleArgumentClassFixedBugByHelperClass::<span style="color: blue">operator </span>==(<span style="color: blue">const </span>SingleArgumentClassFixedBugByHelperClass&amp; rhs){
    <span style="color: blue">if</span>(_inner == rhs._inner)
        <span style="color: blue">return true</span>;
    <span style="color: blue">return false</span>;
}


<span style="color: blue">void </span>Assert(<span style="color: blue">bool </span>status,
        std::string strTrue = std::string(<span style="color: #a31515">"assert result is true;"</span>),
        std::string strFalse = std::string(<span style="color: #a31515">"assert result is false;"</span>));
<span style="color: blue">int </span>main(<span style="color: blue">void</span>){
    SingleArgumentClass obj(3);
    std::cout &lt;&lt; obj.str() &lt;&lt; std::endl;

    <span style="color: green">// our purpose.
    </span>SingleArgumentClass obj1(1);
    SingleArgumentClass obj2(1);
    Assert(obj1 == obj2, <span style="color: #a31515">"obj1 == obj2"</span>, <span style="color: #a31515">"obj1 != obj2"</span>);

    <span style="color: blue">int </span>i = 3;
    <span style="color: green">// warning!!!
    // obj is a SingleArgumentClass object.
    // i is a integer.
    // operator== only define the equal between two SingleArgumentClass object.
    // In fact:
    //    obj == i:
    //        1.compiler found the operator== require two SingleArgumentClass object.
    //        2.compiler try to find a cast method for casting int to SingleArgumentClass.
    //        3.compiler found it can use the SingleArguementClass.Ctor(int)
    //            to create a new SingleArgumentClass.
    //         4.compiler try to create a new SingleArgumentClass object from i.
    //        5.so it without any warning and error, but it's logical not we need.
    </span>Assert(obj == i, <span style="color: #a31515">"obj == i //right?"</span>, <span style="color: #a31515">"obj != i"</span>);
    <span style="color: green">// Assert(i == obj); // Compile ERROR: no match for 'operator==' in 'i == obj'

    // it's may encounter a compile-time error.
    // GNU G++: no match for 'operator==' in 'objFixed == i'    single_argument_ctor.cpp    single_argument_ctor/src    106    C/C++ Problem
    // MSVC: 错误    1    error C2679: 二进制“==”: 没有找到接受“int”类型的右操作数的运算符(或没有可接受的转换)    {projectpath}\single_argument_ctor\src\single_argument_ctor.cpp    107    single_argument_ctor
    </span>SingleArgumentClassFixedBugByExplicitKeyword objFixed(3);
    <span style="color: green">// Assert(objFixed == i, "objFixed == i", "objFixed != i");

    </span>SingleArgumentClassFixedBugByHelperClass objFixedByHelper1(3);
    SingleArgumentClassFixedBugByHelperClass objFixedByHelper2(3);
    <span style="color: green">// it's may encounter a compile-time error.
    // GNU G++: no match for 'operator==' in 'objFixedAuto1 == i'    single_argument_ctor.cpp    single_argument_ctor/src    158    C/C++ Problem
    // MSVC: 错误    1    error C2679: 二进制“==”: 没有找到接受“int”类型的右操作数的运算符(或没有可接受的转换)    {projectpath}\single_argument_ctor\src\single_argument_ctor.cpp    163    single_argument_ctor
    // Assert(objFixedByHelper1 == i);
</span>}
<span style="color: blue">void </span>Assert(<span style="color: blue">bool </span>status,
        std::string strTrue, std::string strFalse)
{
    std::cout &lt;&lt; (status  strTrue : strFalse) &lt;&lt; std::endl;
}
</pre><a href="http://11011.net/software/vspaste"></a>
<p>解决方法：</p>
<p>1、explicit关键字，在单参数构造函数前使用explicit参数，可以避免单参数构造函数被用于隐式转换。</p>
<p>2、利用中间类的方式，详见代码“SingleArgumentClassFixedBugByHelperClass相关部分”。如果编译器不支持解决方法1，则建议使用此方法。上面代码所提及的两款主流编译器均支持explicit关键字。</p><img src ="http://www.cppblog.com/mymsdn/aggbug/110879.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2010-03-29 15:37 <a href="http://www.cppblog.com/mymsdn/archive/2010/03/29/single-argument-construct.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[C++]namespace&amp;amp;using keyword</title><link>http://www.cppblog.com/mymsdn/archive/2010/03/29/namespace-using-keywords.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Mon, 29 Mar 2010 05:28:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2010/03/29/namespace-using-keywords.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/110846.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2010/03/29/namespace-using-keywords.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/110846.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/110846.html</trackback:ping><description><![CDATA[<!--MyMSDN style!--><link rel="stylesheet" type="text/css" href="http://files.cnblogs.com/volnet/gocool.css"> <style type="text/css">
body{background-color:#eeeeee;}
</style>  <p>有时候我们可以用namespace来组织命名空间。</p> <p>有时候我们又希望将一些较深层次的类变成我们比较容易访问的对象。</p> <p>下面的代码提供了一种简单的示例来满足这样的需求。</p> <p>1、用namespace来组织各个类的层级关系。</p> <p>2、用using关键字，将深层次结构暴露到较外层。</p><pre class="gc-code"><span style="color: #3f7f5f">//============================================================================
// Name        : namespace.cpp
// Author      : Volnet
// Version     :
// Copyright   : reserve by volnet@tom.com
// Description : namespace in C++, Ansi-style
//============================================================================

</span><span style="color: #7f0055">#include </span><span style="color: #2a00ff">&lt;iostream&gt;

</span><span style="color: #7f0055">namespace </span>volnet {
    <span style="color: #7f0055">namespace </span>extensions {
        <span style="color: #7f0055">class </span><span style="color: #005032">_Console </span>{
        <span style="color: #7f0055">public</span>:
            <span style="color: #7f0055">void </span>WriteLine(std::<span style="color: #005032">string</span>);
        };
    }
    <span style="color: #7f0055">using </span>extensions::_Console;
}
<span style="color: #7f0055">using namespace </span>volnet;
<span style="color: #005032">_Console </span>Console;

<span style="color: #7f0055">void
</span>_Console::WriteLine(std::<span style="color: #005032">string </span>s) {
    std::cout &lt;&lt; s &lt;&lt; std::endl;
}

<span style="color: #7f0055">using namespace </span>std;

<span style="color: #7f0055">int </span>main() {
    Console.WriteLine(std::<span style="color: #005032">string</span>(<span style="color: #2a00ff">"I'm volnet!"</span>));
    <span style="color: #7f0055">return </span>0;
}<br></pre><img src ="http://www.cppblog.com/mymsdn/aggbug/110846.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2010-03-29 13:28 <a href="http://www.cppblog.com/mymsdn/archive/2010/03/29/namespace-using-keywords.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>boost::tuple</title><link>http://www.cppblog.com/mymsdn/archive/2010/03/25/110537.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Thu, 25 Mar 2010 09:46:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2010/03/25/110537.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/110537.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2010/03/25/110537.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/110537.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/110537.html</trackback:ping><description><![CDATA[<!--MyMSDN style!--><link rel="stylesheet" type="text/css" href="http://files.cnblogs.com/volnet/gocool.css"> <style type="text/css">
body{background-color:#eeeeee;}
</style> <pre class="gc-code">boost::<span style="color: #005032">tuple</span>&lt;<span style="color: #005032">derived</span>&gt; tup4;
boost::<span style="color: #005032">tuple</span>&lt;<span style="color: #005032">base</span>&gt; tup5;
tup5 = tup4;
tup4.get&lt;0&gt;().test();
tup5.get&lt;0&gt;().test(); <span style="color: #3f7f5f">// 丢失多态性<br>
</span><span style="color: #005032">derived </span>d;
boost::<span style="color: #005032">tuple</span>&lt;<span style="color: #005032">derived</span>*&gt; tup6(&amp;d);
boost::<span style="color: #005032">tuple</span>&lt;<span style="color: #005032">base</span>*&gt; tup7;
tup7 = tup6;
tup6.get&lt;0&gt;()-&gt;test();
tup7.get&lt;0&gt;()-&gt;test(); <span style="color: #3f7f5f">// 恢复多态性（方法1）

</span>boost::<span style="color: #005032">tuple</span>&lt;<span style="color: #005032">derived</span>&amp;&gt; tup8(d);
boost::<span style="color: #005032">tuple</span>&lt;<span style="color: #005032">base</span>&amp;&gt; tup9(tup8);
<span style="color: #3f7f5f"><br>// tup9 = tup8; 不能使用该方法，因为无法对引用赋值。
</span>tup8.get&lt;0&gt;().test();
tup9.get&lt;0&gt;().test(); <span style="color: #3f7f5f">// 恢复多态性（方法2）</span></pre><pre class="gc-code"><span style="color: #3f7f5f">/*
 * tuple.cpp
 *
 *  Created on: 2010-3-25
 *      Author: GoCool
 */
</span><span style="color: #7f0055">#include </span><span style="color: #2a00ff">&lt;stdlib.h&gt;
</span><span style="color: #7f0055">#include </span><span style="color: #2a00ff">&lt;iostream&gt;
</span><span style="color: #7f0055">#include </span><span style="color: #2a00ff">&lt;boost/tuple/tuple.hpp&gt;
</span><span style="color: #7f0055">#include </span><span style="color: #2a00ff">&lt;boost/tuple/tuple_io.hpp&gt;
</span><span style="color: #7f0055">#include </span><span style="color: #2a00ff">"../header/baseClass.h"

</span><span style="color: #7f0055">using namespace </span>std;
<span style="color: #7f0055">class </span><span style="color: #005032">X </span>{
  X();
<span style="color: #7f0055">public</span>:
  X(std::<span style="color: #005032">string</span>){}
};
<span style="color: #7f0055">class </span><span style="color: #005032">Y </span>{
  Y(<span style="color: #7f0055">const </span><span style="color: #005032">Y</span>&amp;);
<span style="color: #7f0055">public</span>:
  Y(){}
};
<span style="color: #7f0055">class </span><span style="color: #005032">A </span>{
};
<span style="color: #7f0055">bool </span>operator==(<span style="color: #005032">A</span>, <span style="color: #005032">A</span>) { std::cout &lt;&lt; <span style="color: #2a00ff">"All the same to me..."</span>; <span style="color: #7f0055">return true</span>; }
<span style="color: #7f0055">void </span>f(<span style="color: #7f0055">int </span>i);

<span style="color: #7f0055">void </span>cut_off_rule(<span style="color: #7f0055">void</span>);
<span style="color: #7f0055">int </span>main(<span style="color: #7f0055">void</span>){
    <span style="color: #3f7f5f">// add a new tuple
    </span>boost::<span style="color: #005032">tuple</span>&lt;<span style="color: #7f0055">int</span>,<span style="color: #7f0055">double</span>,std::<span style="color: #005032">string</span>&gt;   triple(42, 3.14, <span style="color: #2a00ff">"My first tuple!"</span>);
    <span style="color: #7f0055">int </span>a = triple.get&lt;0&gt;();
    ++a;
    cout &lt;&lt; a &lt;&lt; endl;
    cout &lt;&lt; triple &lt;&lt; endl;

    cut_off_rule();

    boost::<span style="color: #005032">tuple</span>&lt;<span style="color: #7f0055">int</span>, <span style="color: #7f0055">double</span>&gt; pair = boost::make_tuple(21, 22.5);
    cout &lt;&lt; pair &lt;&lt; endl;

    cut_off_rule();

    <span style="color: #7f0055">int </span>pair_element_1 = -1;
    <span style="color: #7f0055">double </span>pair_element_2 = -1;
    boost::tie(pair_element_1, pair_element_2) = pair;

    cout &lt;&lt; pair_element_1 &lt;&lt; <span style="color: #2a00ff">"," </span>&lt;&lt; pair_element_2 &lt;&lt; endl;

    cut_off_rule();

    boost::<span style="color: #005032">tuple</span>&lt;<span style="color: #7f0055">int</span>,std::<span style="color: #005032">string</span>,<span style="color: #005032">derived</span>&gt; tup1(-5,<span style="color: #2a00ff">"Tuples"</span>);
    boost::<span style="color: #005032">tuple</span>&lt;<span style="color: #7f0055">unsigned int</span>,std::<span style="color: #005032">string</span>,<span style="color: #005032">base</span>&gt; tup2;
    tup2=tup1;
    tup2.get&lt;2&gt;().test();
    std::cout &lt;&lt; <span style="color: #2a00ff">"Interesting value: " </span>&lt;&lt; tup2.get&lt;0&gt;() &lt;&lt; <span style="color: #2a00ff">'\n'</span>;
    <span style="color: #7f0055">const </span>boost::<span style="color: #005032">tuple</span>&lt;<span style="color: #7f0055">double</span>,std::<span style="color: #005032">string</span>,<span style="color: #005032">base</span>&gt; tup3(tup2);
    <span style="color: #3f7f5f">// Description    Resource    Path    Location    Type
    // assignment of read-only location    tuple.cpp    boost_tuple/src    45    C/C++ Problem
    // tup3.get&lt;0&gt;()=3.14;
</span><span style="color: #3f7f5f">
    </span>cut_off_rule();

    boost::<span style="color: #005032">tuple</span>&lt;<span style="color: #005032">X</span>,<span style="color: #005032">X</span>,<span style="color: #005032">X</span>&gt; obj = boost::<span style="color: #005032">tuple</span>&lt;<span style="color: #005032">X</span>,<span style="color: #005032">X</span>,<span style="color: #005032">X</span>&gt;(<span style="color: #005032">string</span>(<span style="color: #2a00ff">"Jaba"</span>), <span style="color: #005032">string</span>(<span style="color: #2a00ff">"Daba"</span>), <span style="color: #005032">string</span>(<span style="color: #2a00ff">"Duu"</span>)); <span style="color: #3f7f5f">// ok

    </span>cut_off_rule();

    <span style="color: #7f0055">double </span>dNum = 5;
    boost::<span style="color: #005032">tuple</span>&lt;<span style="color: #7f0055">double</span>&amp;&gt; numTuple(dNum);               <span style="color: #3f7f5f">// ok

    // boost::tuple&lt;double&amp;&gt;(dNum+3.14);          // error: cannot initialize
                                    // non-const reference with a temporary

    </span>boost::<span style="color: #005032">tuple</span>&lt;<span style="color: #7f0055">const double</span>&amp;&gt;(dNum+3.14);    <span style="color: #3f7f5f">// ok, but dangerous:
                                    // the element becomes a dangling reference
    </span>cut_off_rule();

    <span style="color: #3f7f5f">// char arr[2] = {'a', 'b'};
    // boost::tuple&lt;char[2]&gt;(arr); // error, arrays can not be copied
    // boost::tuple&lt;char[2], Y&gt;(arr, Y()); // error, neither arrays nor Y can be copied

    </span>boost::<span style="color: #005032">tuple</span>&lt;<span style="color: #7f0055">char</span>[2], <span style="color: #005032">Y</span>&gt;();       <span style="color: #3f7f5f">// ok

    </span>cut_off_rule();

    boost::<span style="color: #005032">tuple</span>&lt;<span style="color: #7f0055">void </span>(*)(<span style="color: #7f0055">int</span>)&gt; pFTuple1 = boost::make_tuple(&amp;f);
    pFTuple1.get&lt;0&gt;()(10);

    boost::<span style="color: #005032">tuple</span>&lt;<span style="color: #7f0055">void </span>(*)(<span style="color: #7f0055">int</span>)&gt; pFTuple2 = boost::make_tuple(boost::ref(f));
    pFTuple2.get&lt;0&gt;()(20);

    boost::<span style="color: #005032">tuple</span>&lt;<span style="color: #7f0055">void </span>(&amp;)(<span style="color: #7f0055">int</span>)&gt; pFTuple3(f);
    pFTuple3.get&lt;0&gt;()(30);

    boost::<span style="color: #005032">tuple</span>&lt;boost::<span style="color: #005032">tuple</span>&lt;<span style="color: #7f0055">void </span>(&amp;)(<span style="color: #7f0055">int</span>)&gt; &gt; pFTuple4(f);
    pFTuple4.get&lt;0&gt;().get&lt;0&gt;()(40);

    cut_off_rule();

    <span style="color: #3f7f5f">// boost::tuple&lt;int, char&gt; stdPairToTuple = std::make_pair(1, 'a');

    </span>cut_off_rule();

    boost::<span style="color: #005032">tuple</span>&lt;std::<span style="color: #005032">string</span>, <span style="color: #7f0055">int</span>, <span style="color: #005032">A</span>&gt; t1(std::<span style="color: #005032">string</span>(<span style="color: #2a00ff">"same?"</span>), 2, A());
    boost::<span style="color: #005032">tuple</span>&lt;std::<span style="color: #005032">string</span>, <span style="color: #7f0055">long</span>&gt; t2(std::<span style="color: #005032">string</span>(<span style="color: #2a00ff">"same?"</span>), 2);
    boost::<span style="color: #005032">tuple</span>&lt;std::<span style="color: #005032">string</span>, <span style="color: #7f0055">long</span>&gt; t3(std::<span style="color: #005032">string</span>(<span style="color: #2a00ff">"different"</span>), 3);
    <span style="color: #3f7f5f">// t1 == t2;        // true

    </span>cut_off_rule();

    <span style="color: #7f0055">int </span>i; <span style="color: #7f0055">char </span>c;
    boost::tie(i, c) = std::make_pair(1, <span style="color: #2a00ff">'a'</span>);
    cout &lt;&lt; i &lt;&lt; <span style="color: #2a00ff">" " </span>&lt;&lt; c &lt;&lt; endl;

    cut_off_rule();

    boost::tie(boost::tuples::ignore, c) = std::make_pair(1, <span style="color: #2a00ff">'a'</span>);
    cout &lt;&lt; c &lt;&lt; endl;

    cut_off_rule();

    <span style="color: #7f0055">int </span>myX = -1;
    <span style="color: #7f0055">double </span>myY = -2;
    boost::<span style="color: #005032">tuple</span>&lt;<span style="color: #7f0055">int</span>, <span style="color: #7f0055">double</span>&gt; f2(2);
    boost::tie(myX, myY) = f2; <span style="color: #3f7f5f">// #2
    </span>cout &lt;&lt; <span style="color: #2a00ff">"myX = " </span>&lt;&lt; myX &lt;&lt; <span style="color: #2a00ff">", myY = " </span>&lt;&lt;myY &lt;&lt; endl;
}
<span style="color: #7f0055">void </span>cut_off_rule(<span style="color: #7f0055">void</span>) {
    cout &lt;&lt; <span style="color: #2a00ff">"-----------------------------------" </span>&lt;&lt; endl;
}

<span style="color: #7f0055">void </span>f(<span style="color: #7f0055">int </span>i) {
    cout &lt;&lt; <span style="color: #2a00ff">"f(" </span>&lt;&lt; i &lt;&lt; <span style="color: #2a00ff">")" </span>&lt;&lt; endl;
}


</pre><a href="http://11011.net/software/vspaste"></a>
<p>tuple是boost库中一个类似标准std::pair库库，但pair只能支持两种元素，而tuple则可以支持大于两种的。</p>
<p>更多详解：<a title="http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_users_guide.html" href="http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_users_guide.html">http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_users_guide.html</a></p>
<p>以下内容直接引自原文：</p>
<p>
<div class="note"><br>&nbsp; <h3><img alt="Boost C++ Libraries" src="http://www.boost.org/gfx/space.png"><a href="http://www.boost.org/">Boost C++ Libraries</a></h3>
<p>“...one of the most highly regarded and expertly designed C++ library projects in the world.” — <a href="http://www.gotw.ca/">Herb Sutter</a> and <a href="http://en.wikipedia.org/wiki/Andrei_Alexandrescu">Andrei Alexandrescu</a>, <a href="http://safari.awprofessional.com/?XmlId=0321113586">C++ Coding Standards</a> 
<ul>
<li><a href="http://www.boost.org/">Welcome</a> 
<li><a href="http://www.boost.org/users/">Introduction</a> 
<li><a href="http://www.boost.org/community/">Community</a> 
<li><a href="http://www.boost.org/development/">Development</a> 
<li><a href="http://www.boost.org/support/">Support</a> 
<li><a href="http://www.boost.org/doc/">Documentation</a> 
<li><a href="http://www.boost.org/map.html">Index</a></li></ul>
<p><img alt="C++ 
Boost" src="http://www.boost.org/doc/libs/1_42_0/boost.png" width="277" height="86"> 
<h3>The Boost Tuple Library</h3>
<p>A tuple (or <i>n</i>-tuple) is a fixed size collection of elements. Pairs, triples, quadruples etc. are tuples. In a programming language, a tuple is a data object containing other objects as elements. These element objects may be of different types. 
<p>Tuples are convenient in many circumstances. For instance, tuples make it easy to define functions that return more than one value. 
<p>Some programming languages, such as ML, Python and Haskell, have built-in tuple constructs. Unfortunately C++ does not. To compensate for this "deficiency", the Boost Tuple Library implements a tuple construct using templates. 
<h4>Table of Contents</h4>
<ol>
<li><a href="http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_users_guide.html#using_library">Using the library</a> 
<li><a href="http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_users_guide.html#tuple_types">Tuple types</a> 
<li><a href="http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_users_guide.html#constructing_tuples">Constructing tuples</a> 
<li><a href="http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_users_guide.html#accessing_elements">Accessing tuple elements</a> 
<li><a href="http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_users_guide.html#construction_and_assignment">Copy construction and tuple assignment</a> 
<li><a href="http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_users_guide.html#relational_operators">Relational operators</a> 
<li><a href="http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_users_guide.html#tiers">Tiers</a> 
<li><a href="http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_users_guide.html#streaming">Streaming</a> 
<li><a href="http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_users_guide.html#performance">Performance</a> 
<li><a href="http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_users_guide.html#portability">Portability</a> 
<li><a href="http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_users_guide.html#thanks">Acknowledgements</a> 
<li><a href="http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_users_guide.html#references">References</a></li></ol>
<h6>More details</h6>
<p><a href="http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_advanced_interface.html">Advanced features</a> (describes some metafunctions etc.). 
<p><a href="http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/design_decisions_rationale.html">Rationale behind some design/implementation decisions.</a> 
<h4><a name="1279665a36dfcc06_using_library">Using the library</a></h4>
<p>To use the library, just include:<pre><code>#include "boost/tuple/tuple.hpp"</code></pre>
<p>Comparison operators can be included with:<pre><code>#include "boost/tuple/tuple_comparison.hpp"</code></pre>
<p>To use tuple input and output operators,<pre><code>#include "boost/tuple/tuple_io.hpp"</code></pre>
<p>Both <code>tuple_io.hpp</code> and <code>tuple_comparison.hpp</code> include <code>tuple.hpp</code>. 
<p>All definitions are in namespace <code>::boost::tuples</code>, but the most common names are lifted to namespace <code>::boost</code> with using declarations. These names are: <code>tuple</code>, <code>make_tuple</code>, <code>tie</code> and <code>get</code>. Further, <code>ref</code> and <code>cref</code> are defined directly under the <code>::boost</code> namespace. 
<h4><a name="1279665a36dfcc06_tuple_types">Tuple types</a></h4>
<p>A tuple type is an instantiation of the <code>tuple</code> template. The template parameters specify the types of the tuple elements. The current version supports tuples with 0-10 elements. If necessary, the upper limit can be increased up to, say, a few dozen elements. The data element can be any C++ type. Note that <code>void</code> and plain function types are valid C++ types, but objects of such types cannot exist. Hence, if a tuple type contains such types as elements, the tuple type can exist, but not an object of that type. There are natural limitations for element types that cannot be copied, or that are not default constructible (see 'Constructing tuples' below). 
<p>For example, the following definitions are valid tuple instantiations (<code>A</code>, <code>B</code> and <code>C</code> are some user defined classes):<pre><code>tuple&lt;int&gt;<br>tuple&lt;double&amp;, const double&amp;, const double, double*, const double*&gt;<br>tuple&lt;A, int(*)(char, int), B(A::*)(C&amp;), C&gt;<br>tuple&lt;std::string, std::pair&lt;A, B&gt; &gt;<br>
tuple&lt;A*, tuple&lt;const A*, const B&amp;, C&gt;, bool, void*&gt;<br></code></pre>
<h4><a name="1279665a36dfcc06_constructing_tuples">Constructing tuples</a></h4>
<p>The tuple constructor takes the tuple elements as arguments. For an <i>n</i>-element tuple, the constructor can be invoked with <i>k</i> arguments, where 0 &lt;= <i>k</i> &lt;= <i>n</i>. For example:<pre><code>tuple&lt;int, double&gt;() <br>tuple&lt;int, double&gt;(1) <br>tuple&lt;int, double&gt;(1, 3.14)<br></code></pre>
<p>If no initial value for an element is provided, it is default initialized (and hence must be default initializable). For example.<pre><code>class X {<br>  X(); <br>public:<br>  X(std::string);<br>};<br><br>tuple&lt;X,X,X&gt;()                                              // error: no default constructor for X<br>tuple&lt;X,X,X&gt;(string("Jaba"), string("Daba"), string("Duu")) // ok<br>
</code></pre>
<p>In particular, reference types do not have a default initialization: <pre><code>tuple&lt;double&amp;&gt;()                // error: reference must be <br>                                // initialized explicitly<br><br>double d = 5; <br>tuple&lt;double&amp;&gt;(d)               // ok<br><br>
tuple&lt;double&amp;&gt;(d+3.14)          // error: cannot initialize <br>                                // non-const reference with a temporary<br><br>tuple&lt;const double&amp;&gt;(d+3.14)    // ok, but dangerous: <br>
                                // the element becomes a dangling reference <br></code></pre>
<p>Using an initial value for an element that cannot be copied, is a compile time error:<pre><code>class Y { <br>  Y(const Y&amp;); <br>public:<br>  Y();<br>};<br><br>char a[10];<br><br>tuple&lt;char[10], Y&gt;(a, Y()); // error, neither arrays nor Y can be copied<br>tuple&lt;char[10], Y&gt;();       // ok<br>
</code></pre>
<p>Note particularly that the following is perfectly ok:<pre><code>Y y;<br>tuple&lt;char(&amp;)[10], Y&amp;&gt;(a, y); <br></code></pre>
<p>It is possible to come up with a tuple type that cannot be constructed. This occurs if an element that cannot be initialized has a lower index than an element that requires initialization. For example: <code>tuple&lt;char[10], int&amp;&gt;</code>. 
<p>In sum, the tuple construction is semantically just a group of individual elementary constructions. 
<h6><a name="1279665a36dfcc06_make_tuple">The <code>make_tuple</code> function</a></h6>
<p>Tuples can also be constructed using the <code>make_tuple</code> (cf. <code>std::make_pair</code>) helper functions. This makes the construction more convenient, saving the programmer from explicitly specifying the element types:<pre><code>tuple&lt;int, int, double&gt; add_multiply_divide(int a, int b) {<br>  return make_tuple(a+b, a*b, double(a)/double(b));<br>}<br></code></pre>
<p>By default, the element types are deduced to the plain non-reference types. E.g.: <pre><code>void foo(const A&amp; a, B&amp; b) { <br>  ...<br>  make_tuple(a, b);<br></code></pre>
<p>The <code>make_tuple</code> invocation results in a tuple of type <code>tuple&lt;A, B&gt;</code>. 
<p>Sometimes the plain non-reference type is not desired, e.g. if the element type cannot be copied. Therefore, the programmer can control the type deduction and state that a reference to const or reference to non-const type should be used as the element type instead. This is accomplished with two helper template functions: <code>ref</code> and <code>cref</code>. Any argument can be wrapped with these functions to get the desired type. The mechanism does not compromise const correctness since a const object wrapped with <code>ref</code> results in a tuple element with const reference type (see the fifth example below). For example:<pre><code>A a; B b; const A ca = a;<br>make_tuple(cref(a), b);      // creates tuple&lt;const A&amp;, B&gt;<br>make_tuple(ref(a), b);       // creates tuple&lt;A&amp;, B&gt;<br>make_tuple(ref(a), cref(b)); // creates tuple&lt;A&amp;, const B&amp;&gt;<br>
make_tuple(cref(ca));        // creates tuple&lt;const A&amp;&gt;<br>make_tuple(ref(ca));         // creates tuple&lt;const A&amp;&gt;<br></code></pre>
<p>Array arguments to <code>make_tuple</code> functions are deduced to reference to const types by default; there is no need to wrap them with <code>cref</code>. For example:<pre><code>make_tuple("Donald", "Daisy");<br></code></pre>
<p>This creates an object of type <code>tuple&lt;const char (&amp;)[7], const char (&amp;)[6]&gt;</code> (note that the type of a string literal is an array of const characters, not <code>const char*</code>). However, to get <code>make_tuple</code> to create a tuple with an element of a non-const array type one must use the <code>ref</code> wrapper. 
<p>Function pointers are deduced to the plain non-reference type, that is, to plain function pointer. A tuple can also hold a reference to a function, but such a tuple cannot be constructed with <code>make_tuple</code> (a const qualified function type would result, which is illegal):<pre><code>void f(int i);<br>  ...<br>make_tuple(&amp;f); // tuple&lt;void (*)(int)&gt;<br>  ...<br><br><font color="#ff0000">volnet:<br>	boost::tuple&lt;void (&amp;)(int)&gt; pFTuple3(f);</font><br>
	pFTuple3.get&lt;0&gt;()(30);<br><br>tuple&lt;tuple&lt;void (&amp;)(int)&gt; &gt; a(f) // ok<br>make_tuple(f);                    // not ok<br></code></pre>
<h4><a name="1279665a36dfcc06_accessing_elements">Accessing tuple elements</a></h4>
<p>Tuple elements are accessed with the expression:<pre><code>t.get&lt;N&gt;()<br></code></pre>
<p>or<pre><code>get&lt;N&gt;(t)<br></code></pre>
<p>where <code>t</code> is a tuple object and <code>N</code> is a constant integral expression specifying the index of the element to be accessed. Depending on whether <code>t</code> is const or not, <code>get</code> returns the <code>N</code>th element as a reference to const or non-const type. The index of the first element is 0 and thus<code> N</code> must be between 0 and <code>k-1</code>, where <code>k</code> is the number of elements in the tuple. Violations of these constraints are detected at compile time. Examples:<pre><code>double d = 2.7; A a;<br>tuple&lt;int, double&amp;, const A&amp;&gt; t(1, d, a);<br>const tuple&lt;int, double&amp;, const A&amp;&gt; ct = t;<br>  ...<br>int i = get&lt;0&gt;(t); i = t.get&lt;0&gt;();        // ok<br>
int j = get&lt;0&gt;(ct);                       // ok<br>get&lt;0&gt;(t) = 5;                            // ok <br>get&lt;0&gt;(ct) = 5;                           // error, can't assign to const <br>  ...<br>double e = get&lt;1&gt;(t); // ok   <br>
get&lt;1&gt;(t) = 3.14;     // ok <br>get&lt;2&gt;(t) = A();      // error, can't assign to const <br>A aa = get&lt;3&gt;(t);     // error: index out of bounds <br>  ...<br>++get&lt;0&gt;(t);  // ok, can be used as any variable<br>
</code></pre>
<p><font color="#ff8040">Note! The member get functions are not supported with MS Visual C++ compiler. Further, the compiler has trouble with finding the non-member get functions without an explicit namespace qualifier. Hence, all <code>get</code> calls should be qualified as: <code>tuples::get&lt;N&gt;(a_tuple)</code> when writing code that should compile with MSVC++ 6.0. </font>
<h4><a name="1279665a36dfcc06_construction_and_assignment">Copy construction and tuple assignment</a></h4>
<p>A tuple can be copy constructed from another tuple, provided that the element types are element-wise copy constructible. Analogously, a tuple can be assigned to another tuple, provided that the element types are element-wise assignable. For example:<pre><code>class A {};<br>class B : public A {};<br>struct C { C(); C(const B&amp;); };<br><font color="#ff00ff">struct D { operator C() const; };<br></font>tuple&lt;char, B*, B, D&gt; t;<br>  ...<br>tuple&lt;int, A*, C, C&gt; a(t); // ok <br>
a = t;                     // ok <br></code></pre>
<p>In both cases, the conversions performed are: <code>char -&gt; int</code>, <code>B* -&gt; A*</code> (derived class pointer to base class pointer), <code>B -&gt; C</code> (a user defined conversion) and <code>D -&gt; C</code> (a user defined conversion). 
<p>Note that assignment is also defined from <code>std::pair</code> types:<pre><code>tuple&lt;float, int&gt; a = std::make_pair(1, 'a');<br><br><font color="#ff0000">volnet:(Eclipse with MinGW g++<br>conversion from `std::pair&lt;int, char&gt;' to non-scalar type `boost::tuples::tuple&lt;float, int, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type&gt;' requested<br></font>
</code></pre>
<h4><a name="1279665a36dfcc06_relational_operators">Relational operators</a></h4>
<p>Tuples reduce the operators <code>==, !=, &lt;, &gt;, &lt;=</code> and <code>&gt;=</code> to the corresponding elementary operators. This means, that if any of these operators is defined between all elements of two tuples, then the same operator is defined between the tuples as well. The equality operators for two tuples <code>a</code> and <code>b</code> are defined as: 
<ul>
<li><code>a == b</code> iff for each <code>i</code>: <code>a<sub>i</sub> == b<sub>i</sub></code> 
<li><code>a != b</code> iff exists <code>i</code>: <code>a<sub>i</sub> != b<sub>i</sub></code></li></ul>
<p>The operators <code>&lt;, &gt;, &lt;=</code> and <code>&gt;=</code> implement a lexicographical ordering. 
<p>Note that an attempt to compare two tuples of different lengths results in a compile time error. Also, the comparison operators are <i>"short-circuited"</i>: elementary comparisons start from the first elements and are performed only until the result is clear. 
<p>Examples:<pre><code>tuple&lt;std::string, int, A&gt; t1(std::string("same?"), 2, A());<br>tuple&lt;std::string, long, A&gt; t2(std::string("same?"), 2, A());<br>tuple&lt;std::string, long, A&gt; t3(std::string("different"), 3, A());<br>
<br>bool operator==(A, A) { std::cout &lt;&lt; "All the same to me..."; return true; }<br><br>t1 == t2; 		// true<br>t1 == t3;               // false, does not print "All the..."<br></code></pre>
<h4><a name="1279665a36dfcc06_tiers">Tiers</a></h4>
<p><i>Tiers</i> are tuples, where<font color="#ff8040"> all elements are of non-const reference types</font>. They are constructed with a call to the <code>tie</code> function template (cf. <code>make_tuple</code>):<pre><code>int i; char c; double d; <br>  ...<br>tie(i, c, a);<br></code></pre>
<p>The above <code>tie</code> function creates a tuple of type <code>tuple&lt;int&amp;, char&amp;, double&amp;&gt;</code>. The same result could be achieved with the call <code>make_tuple(ref(i), ref(c), ref(a))</code>. 
<p>A tuple that contains non-const references as elements can be used to 'unpack' another tuple into variables. E.g.:<pre><code>int i; char c; double d; <br>tie(i, c, d) = make_tuple(1,'a', 5.5);<br>std::cout &lt;&lt; i &lt;&lt; " " &lt;&lt;  c &lt;&lt; " " &lt;&lt; d;<br></code></pre>
<p>This code prints <code>1 a 5.5</code> to the standard output stream. A tuple unpacking operation like this is found for example in ML and Python. It is convenient when calling functions which return tuples. 
<p>The tying mechanism works with <code>std::pair</code> templates as well:<pre><code>int i; char c;<br>tie(i, c) = std::make_pair(1, 'a');<br></code></pre>
<h6>Ignore</h6>
<p>There is also an object called <code>ignore</code> which allows you to ignore an element assigned by a tuple. The idea is that a function may return a tuple, only part of which you are interested in. For example (note, that <code>ignore</code> is under the <code>tuples</code> subnamespace):<pre><code>char c;<br>tie(tuples::ignore, c) = std::make_pair(1, 'a');<br></code></pre>
<h4><a name="1279665a36dfcc06_streaming">Streaming</a></h4>
<p>The global <code>operator&lt;&lt;</code> has been overloaded for <code>std::ostream</code> such that tuples are output by recursively calling <code>operator&lt;&lt;</code> for each element. 
<p>Analogously, the global <code>operator&gt;&gt;</code> has been overloaded to extract tuples from <code>std::istream</code> by recursively calling <code>operator&gt;&gt;</code> for each element. 
<p>The default delimiter between the elements is space, and the tuple is enclosed in parenthesis. For Example: <pre><code>tuple&lt;float, int, std::string&gt; a(1.0f,  2, std::string("Howdy folks!");<br><br>cout &lt;&lt; a; <br></code></pre>
<p>outputs the tuple as: <code>(1.0 2 Howdy folks!)</code> 
<p>The library defines three <i>manipulators</i> for changing the default behavior: 
<ul>
<li><code>set_open(char)</code> defines the character that is output before the first element. 
<li><code>set_close(char)</code> defines the character that is output after the last element. 
<li><code>set_delimiter(char)</code> defines the delimiter character between elements.</li></ul>
<p>Note, that these manipulators are defined in the <code>tuples</code> subnamespace. For example:<pre><code>cout &lt;&lt; tuples::set_open('[') &lt;&lt; tuples::set_close(']') &lt;&lt; tuples::set_delimiter(',') &lt;&lt; a; <br></code></pre>
<p>outputs the same tuple <code>a</code> as: <code>[1.0,2,Howdy folks!]</code> 
<p>The same manipulators work with <code>operator&gt;&gt;</code> and <code>istream</code> as well. Suppose the <code>cin</code> stream contains the following data: <pre><code>(1 2 3) [4:5]</code></pre>
<p>The code:<pre><code>tuple&lt;int, int, int&gt; i;<br>tuple&lt;int, int&gt; j;<br><br>cin &gt;&gt; i;<br>cin &gt;&gt; tuples::set_open('[') &gt;&gt; tuples::set_close(']') &gt;&gt; tuples::set_delimiter(':');<br>
cin &gt;&gt; j;<br></code></pre>
<p>reads the data into the tuples <code>i</code> and <code>j</code>. 
<p><font color="#ff8040">Note that extracting tuples with <code>std::string</code> or C-style string elements does not generally work, since the streamed tuple representation may not be unambiguously parseable.</font> 
<h4><a name="1279665a36dfcc06_performance">Performance</a></h4>
<p>All tuple access and construction functions are small inlined one-liners. Therefore, a decent compiler can eliminate any extra cost of using tuples compared to using hand-written tuple like classes. Particularly, with a decent compiler there is no performance difference between this code:<pre><code>class hand_made_tuple { <br>  A a; B b; C c;<br>public:<br>  hand_made_tuple(const A&amp; aa, const B&amp; bb, const C&amp; cc) <br>    : a(aa), b(bb), c(cc) {};<br>  A&amp; getA() { return a; };<br>  B&amp; getB() { return b; };<br>
  C&amp; getC() { return c; };<br>};<br><br>hand_made_tuple hmt(A(), B(), C()); <br>hmt.getA(); hmt.getB(); hmt.getC();<br></code></pre>
<p>and this code:<pre><code>tuple&lt;A, B, C&gt; t(A(), B(), C());<br>t.get&lt;0&gt;(); t.get&lt;1&gt;(); t.get&lt;2&gt;(); <br></code></pre>
<p>Note, that there are widely used compilers (e.g. bcc 5.5.1) which fail to optimize this kind of tuple usage. 
<p>Depending on the optimizing ability of the compiler, the tier mechanism may have a small performance penalty compared to using non-const reference parameters as a mechanism for returning multiple values from a function. For example, suppose that the following functions <code>f1</code> and <code>f2</code> have equivalent functionalities:<pre><code>void f1(int&amp;, double&amp;);<br>tuple&lt;int, double&gt; f2();<br></code></pre>
<p>Then, the call #1 may be slightly faster than #2 in the code below:<pre><code>int i; double d;<br>  ...<br>f1(i,d);         // #1<br>tie(i,d) = f2(); // #2<br><br><font color="#ff0000">volnet:<br>
	int myX = -1;<br>	double myY = -2;<br>
	boost::tuple&lt;int, double&gt; f2(2);<br>	boost::tie(myX, myY) = f2; // #2<br>
	cout &lt;&lt; "myX = " &lt;&lt; myX &lt;&lt; ", myY = " &lt;&lt;myY &lt;&lt; endl;</font><br></code></pre>
<p>See [<a href="http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_users_guide.html#publ_1">1</a>, <a href="http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_users_guide.html#publ_2">2</a>] for more in-depth discussions about efficiency. 
<h6>Effect on Compile Time</h6>
<p>Compiling tuples can be slow due to the excessive amount of template instantiations. Depending on the compiler and the tuple length, it may be more than 10 times slower to compile a tuple construct, compared to compiling an equivalent explicitly written class, such as the <code>hand_made_tuple</code> class above. However, as a realistic program is likely to contain a lot of code in addition to tuple definitions, the difference is probably unnoticeable. Compile time increases between 5 and 10 percent were measured for programs which used tuples very frequently. With the same test programs, memory consumption of compiling increased between 22% to 27%. See [<a href="http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_users_guide.html#publ_1">1</a>, <a href="http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_users_guide.html#publ_2">2</a>] for details. 
<h4><a name="1279665a36dfcc06_portability">Portability</a></h4>
<p>The library code is(?) standard C++ and thus the library works with a standard conforming compiler. Below is a list of compilers and known problems with each compiler: 
<p><u>Compiler</u><br><u>Problems</u> 
<p>gcc 2.95<br>- 
<p>edg 2.44<br>- 
<p>Borland 5.5<br>Can't use function pointers or member pointers as tuple elements 
<p>Metrowerks 6.2<br>Can't use <code>ref</code> and <code>cref</code> wrappers 
<p>MS Visual C++<br>No reference elements (<code>tie</code> still works). Can't use <code>ref</code> and <code>cref</code> wrappers 
<h4><a name="1279665a36dfcc06_thanks">Acknowledgements</a></h4>
<p>Gary Powell has been an indispensable helping hand. In particular, stream manipulators for tuples were his idea. Doug Gregor came up with a working version for MSVC, David Abrahams found a way to get rid of most of the restrictions for compilers not supporting partial specialization. Thanks to Jeremy Siek, William Kempf and Jens Maurer for their help and suggestions. The comments by Vesa Karvonen, John Max Skaller, Ed Brey, Beman Dawes, David Abrahams and Hartmut Kaiser helped to improve the library. The idea for the tie mechanism came from an old usenet article by Ian McCulloch, where he proposed something similar for std::pairs. 
<h4><a name="1279665a36dfcc06_references">References</a></h4>
<p><a name="1279665a36dfcc06_publ_1"></a>[1] Järvi J.: <i>Tuples and multiple return values in C++</i>, TUCS Technical Report No 249, 1999. 
<p><a name="1279665a36dfcc06_publ_2"></a>[2] Järvi J.: <i>ML-Style Tuple Assignment in Standard C++ - Extending the Multiple Return Value Formalism</i>, TUCS Technical Report No 267, 1999. 
<p>[3] Järvi J.:<i>Tuple Types and Multiple Return Values</i>, C/C++ Users Journal, August 2001. 
<hr>

<p>Last modified 2003-09-07 
<p>© Copyright <a href="http://www.boost.org/people/jaakko_jarvi.htm">Jaakko Järvi</a> 2001. Permission to copy, use, modify, sell and distribute this software and its documentation is granted provided this copyright notice appears in all copies. This software and its documentation is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose. 
<p><br><br>&nbsp;<font style="background-color: #eecd55" face="PMingLiU"></font></p></div><img src ="http://www.cppblog.com/mymsdn/aggbug/110537.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2010-03-25 17:46 <a href="http://www.cppblog.com/mymsdn/archive/2010/03/25/110537.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C语言位域</title><link>http://www.cppblog.com/mymsdn/archive/2009/12/30/c-bit-field.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Tue, 29 Dec 2009 17:02:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2009/12/30/c-bit-field.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/104425.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2009/12/30/c-bit-field.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/104425.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/104425.html</trackback:ping><description><![CDATA[这个概念显然是知道的，不过刚才忘了，然后写了个程序就明白了，记录一下，也许以后又健忘了：<br>
<div class="gc-code"><span style="color: #008080;">&nbsp;1</span>&nbsp;<span style="color: #000000;">#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">stdio.h</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #000000;">typedef&nbsp;</span><span style="color: #0000ff;">struct</span><span style="color: #000000;">&nbsp;_SimpleType1&nbsp;{<br></span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;Variable1;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">4bytes(32bits)</span><span style="color: #008000;"><br></span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #008000;"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;Variable2;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">4bytes(32bits)</span><span style="color: #008000;"><br></span><span style="color: #008080;">&nbsp;5</span>&nbsp;<span style="color: #008000;"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;Variable3;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">4bytes(32bits)</span><span style="color: #008000;"><br></span><span style="color: #008080;">&nbsp;6</span>&nbsp;<span style="color: #008000;"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;Variable4;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">4bytes(32bits)</span><span style="color: #008000;"><br></span><span style="color: #008080;">&nbsp;7</span>&nbsp;<span style="color: #008000;"></span><span style="color: #000000;">}&nbsp;SimpleType1;<br></span><span style="color: #008080;">&nbsp;8</span>&nbsp;<span style="color: #000000;"><br></span><span style="color: #008080;">&nbsp;9</span>&nbsp;<span style="color: #000000;">typedef&nbsp;</span><span style="color: #0000ff;">struct</span><span style="color: #000000;">&nbsp;_ComplexType1&nbsp;{<br></span><span style="color: #008080;">10</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;Variable1&nbsp;:&nbsp;</span><span style="color: #000000;">8</span><span style="color: #000000;">;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">1bytes(8bits)</span><span style="color: #008000;"><br></span><span style="color: #008080;">11</span>&nbsp;<span style="color: #008000;"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;Variable2&nbsp;:&nbsp;</span><span style="color: #000000;">8</span><span style="color: #000000;">;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">1bytes(8bits)</span><span style="color: #008000;"><br></span><span style="color: #008080;">12</span>&nbsp;<span style="color: #008000;"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;Variable3&nbsp;:&nbsp;</span><span style="color: #000000;">8</span><span style="color: #000000;">;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">1bytes(8bits)</span><span style="color: #008000;"><br></span><span style="color: #008080;">13</span>&nbsp;<span style="color: #008000;"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;Variable4&nbsp;:&nbsp;</span><span style="color: #000000;">8</span><span style="color: #000000;">;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">1bytes(8bits)</span><span style="color: #008000;"><br></span><span style="color: #008080;">14</span>&nbsp;<span style="color: #008000;"></span><span style="color: #000000;">}&nbsp;ComplexType1;<br></span><span style="color: #008080;">15</span>&nbsp;<span style="color: #000000;"><br></span><span style="color: #008080;">16</span>&nbsp;<span style="color: #000000;">typedef&nbsp;</span><span style="color: #0000ff;">struct</span><span style="color: #000000;">&nbsp;_ComplexType2&nbsp;{<br></span><span style="color: #008080;">17</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;Variable1&nbsp;:&nbsp;</span><span style="color: #000000;">8</span><span style="color: #000000;">;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">1bytes(8bits)</span><span style="color: #008000;"><br></span><span style="color: #008080;">18</span>&nbsp;<span style="color: #008000;"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;Variable2&nbsp;:&nbsp;</span><span style="color: #000000;">8</span><span style="color: #000000;">;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">1bytes(8bits)</span><span style="color: #008000;"><br></span><span style="color: #008080;">19</span>&nbsp;<span style="color: #008000;"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;Variable3&nbsp;:&nbsp;</span><span style="color: #000000;">8</span><span style="color: #000000;">;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">1bytes(8bits)</span><span style="color: #008000;"><br></span><span style="color: #008080;">20</span>&nbsp;<span style="color: #008000;"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;Variable4&nbsp;:&nbsp;</span><span style="color: #000000;">8</span><span style="color: #000000;">;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">1bytes(8bits)</span><span style="color: #008000;"><br></span><span style="color: #008080;">21</span>&nbsp;<span style="color: #008000;"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;Variable5&nbsp;:&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">0.125bytes(1bits)&nbsp;but&nbsp;the&nbsp;it&nbsp;also&nbsp;hold&nbsp;32bits&nbsp;</span><span style="color: #008000;"><br></span><span style="color: #008080;">22</span>&nbsp;<span style="color: #008000;"></span><span style="color: #000000;">}&nbsp;ComplexType2;<br></span><span style="color: #008080;">23</span>&nbsp;<span style="color: #000000;"><br></span><span style="color: #008080;">24</span>&nbsp;<span style="color: #000000;"></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;main(</span><span style="color: #0000ff;">void</span><span style="color: #000000;">){<br></span><span style="color: #008080;">25</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000;">"</span><span style="color: #000000;">sizeof&nbsp;SimpleType1&nbsp;=&nbsp;%d\n</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(SimpleType1));<br></span><span style="color: #008080;">26</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000;">"</span><span style="color: #000000;">sizeof&nbsp;ComplexType1&nbsp;=&nbsp;%d\n</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(ComplexType1));<br></span><span style="color: #008080;">27</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000;">"</span><span style="color: #000000;">sizeof&nbsp;ComplexType2&nbsp;=&nbsp;%d\n</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(ComplexType2));<br></span><span style="color: #008080;">28</span>&nbsp;<span style="color: #000000;">}</span></div>
结果：<br>sizeof SimpleType1 = 16<br>sizeof ComplexType1 = 4<br>sizeof ComplexType2 = 8<br><br><img src ="http://www.cppblog.com/mymsdn/aggbug/104425.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2009-12-30 01:02 <a href="http://www.cppblog.com/mymsdn/archive/2009/12/30/c-bit-field.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于线程同步的一些总结（用户模式/内核模式）</title><link>http://www.cppblog.com/mymsdn/archive/2009/12/26/about-multithread-sync.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Fri, 25 Dec 2009 21:53:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2009/12/26/about-multithread-sync.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/104111.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2009/12/26/about-multithread-sync.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/104111.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/104111.html</trackback:ping><description><![CDATA[<p><h3>自旋锁同步</h3><ol><li>一般是为了内核态下各个派遣函数之间做同步作用的。</li><li>原理是（单CPU）将IRQL从软件中断提升到硬件中断。PASSIVE_LEVEL->DISPATCH_LEVEL。因为在DISPATCH_LEVEL中是不会出现线程切换的（只有高级别能打断低级别，而低级别不能打断高级别）。</li><li>因为分页内存将导致如果线程切换的时候会引起分页数据交换，数据交换是通过引发页故障来实现的，而页故障是不允许出现在DISPATCH_LEVEL中的，否则将引起系统崩溃（PASSIVE_LEVEL则允许）。驱动程序的StartIO例程、DPC例程、中断服务例程都运行在DISPATCH_LEVEL或者更高的IRQL。因此这些例程不能使用分页内存，否则将导致系统崩溃。</li><li>自旋锁在不同IRP之间同步的时候，则需要放在DeviceExtension中传递。</li></ol></p><p><h3>互锁</h3><ol><li>类似于number++; //汇编后将不止一条语句，非原子操作number--; //同上因为语句会变成多句，在线程切换的时候，两个线程下的该例程将会交织在一起执行，导致错误。可以：<div class="gc-code">先加锁<br />number++;<br />解锁<br />再加锁<br />number--;<br />解锁<br /></div>来实现两句话的同步（按指定顺序执行，而不受到线程切换的影响）加锁解锁可以使用自旋锁</li><li>在系统中提供了Interlocked***/ExInterlocked***实现</li></ol></p><p><h3>信号灯同步</h3><ol><li>线程1关闭信号灯，以至于使用Wait****的时候，当前线程处于暂停状态。</li><li>线程2的作用就是在执行结束后，点亮信号灯（增加计数器）。当线程切换回来的时候，线程1就因为计数器不是0而使信号灯处于激活状态，从而继续执行线程1。</li></ol></p><p><h3>事件的同步</h3>（不能递归获取互斥体）<ol><li>主线程在辅助线程上设置了事件，如果不使用Wait**等待事件返回，则主线程可能直接执行完毕了，而导致辅助线程还在执行。</li><li>使用Wait****可以使主线程等待事件执行完成。</li></ol></p><p><h3>互斥体同步</h3>（允许递归获取互斥体（得到互斥体的线程还可以再次获得这个互斥体，或者说互斥体对于已经获得互斥体的线程不产生&#8220;互斥&#8221;关系））<ol><li>创建一个互斥体对象，将互斥体对象传递给多个线程。</li><li>在每个线程操作的步骤中，调用Wait*****，如果互斥体处于激活（内部维护一个计数器），则继续执行后续代码，并在调用结束后恢复互斥体Release****，这样当别的线程试图使用互斥体后面的代码的时候，因为互斥体状态未激活，则无法继续执行代码。</li></ol></p><p><h3>快速互斥体同步</h3><ol><li>与互斥体同步类似，唯一区别是不允许递归获取互斥体</li></ol></p><img src ="http://www.cppblog.com/mymsdn/aggbug/104111.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2009-12-26 05:53 <a href="http://www.cppblog.com/mymsdn/archive/2009/12/26/about-multithread-sync.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何编译TrueCrypt源码</title><link>http://www.cppblog.com/mymsdn/archive/2009/12/23/how-to-complie-TrueCrypt-63a.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Wed, 23 Dec 2009 15:47:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2009/12/23/how-to-complie-TrueCrypt-63a.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/103863.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2009/12/23/how-to-complie-TrueCrypt-63a.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/103863.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/103863.html</trackback:ping><description><![CDATA[<h3>相关配置</h3><ul>&#160;&#160;&#160; <li>Intel x86 Core 2 Duo</li>&#160;&#160;&#160; <li>Windows 7 Ultimate x86 version</li>&#160;&#160;&#160; <li>Windows Driver Develop Kit 7600.16385.0</li>&#160;&#160;&#160; <li>TrueCrypt 6.3a Source.zip</li>&#160;&#160;&#160; <li>Microsoft Visual Studio 2008 SP1 (VC++ 2008)</li>&#160;&#160;&#160; <li>Microsoft Visual Studio VC++ 1.52</li>&#160;&#160;&#160; <li>NASM version 2.07 compiled on Jul 19 2009</li>&#160;&#160;&#160; <li>gzip 1.2.4 Win32 (02 Dec 97)</li>&#160;&#160;&#160; <li>......</li></ul><br /><h3>配置TrueCrypt</h3><ol><li>下载MSVC++ 1.52，安装在C盘下：C:\MSVC<br /></li><li>下载NASM，也安装在C盘下：C:\NASM<br />http://www.nasm.us/pub/nasm/releasebuilds/2.07/win32/<br /></li><li>下载GZIP，也安装在C盘下：C:\gzip<br /></li><li>下载并安装WINDDK，http://www.microsoft.com/whdc/DevTools/WDK/WDKpkg.mspx<br />我将它们安装在D盘，路径：D:\WinDDK<br /></li><li>设置系统变量（（WIN7）控制面板\所有控制面板项\系统\高级系统设置\环境变量）：系统变量中，新增：<br />变量1：MSVC16_ROOT&#160;&#160;&#160; 值：C:\MSVC<br />变量2：WINDDK_ROOT&#160;&#160;&#160; 值：D:\WinDDK\7600.16385.0<br />其中7600.16385.0为WinDDK的第二级目录名，同时也是版本号，7600是Windows7的发行版本号。<br />双击变量：PATH，在其值的末尾补上：C:\NASM;C:\gzip<br />目的是为了让我们可以直接在命令行实用nasm以及gzip作为命令行。<br /></li><li>下载PKCS11，三个文件，右键另存为即可。<br />http://svn.openvpn.net/projects/openvpn/test/time/openvpn/pkcs11-headers/<br />将三个文件（pkcs11.h、pkcs11f.h、pkcs11t.h）拷贝到源码下的Common文件夹下，我的源码放在D盘根目录，三个源码我就放在&#8220;D:\TrueCrypt\Common&#8221;文件夹中。<br /></li><li>编译，会发现有两个错误。<br />CKR_NEW_PIN_MODE和CKR_NEXT_OTP未定义，补充定义一下即可。<br />在d:\TrueCrypt\Common\pkcs11t.h文件里（请根据您自己的路径进行复制）<br />这里将它们设置为：<br /><div class="gc-code">#define CKR_NEW_PIN_MODE&#160;&#160;&#160;&#160;&#160; 0x000001B0<br />#define CKR_NEXT_OTP&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 0x000001B1<br /></div>我的方法是找到实用它的语句附近的同类语句，找到相同的定义，在其下方添加。<br />比如：<br /><div class="gc-code">&#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; TC_TOKEN_ERR (CKR_MUTEX_NOT_LOCKED)<br />&#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; TC_TOKEN_ERR (CKR_NEW_PIN_MODE)<br />&#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; TC_TOKEN_ERR (CKR_NEXT_OTP)<br /></div>这三句话放在一起，后两句有问题，但第一句正常，则查找CKR_MUTEX_NOT_LOCKED的存放位置，在其下方添加如上两句，其中定义的值参考<br />http://www.cryptsoft.com/pkcs11doc/STANDARD/include/v220/otp-pkcs11.h，这里的值只不过是一种错误码，只要它不重复，就可以了。<br /></li><li>再编译，可能会遇到一些警告：<br /><ol><li>nasm.exe正在停止，而因为没有正确执行，又导致&#8220;fatal error LNK1136: invalid or corrupt file&#8221;错误。<br />遇到这个可能是因为你的nasm正在试图编译ase_amdX64.asm文件，而nasm对64位的asm编译对你可能意义不大，起码对我而言是这样的，于是，我就将它转成编译x86体系架构的，也许是因为参数配置的问题，你可以尝试别的方案，如果有更好的话，请告诉我。<br />这里我搜索：x64、asm等关键字，修改d:\TrueCrypt\Crypto\Makefile.inc文件为下面这样即可：<br /><div class="gc-code">行1&#160;&#160;&#160; !if "$(TC_ARCH)" == "x86"<br />行2&#160;&#160;&#160; TC_OBJ_FORMAT = win32<br />行3&#160;&#160;&#160; !else<br />行4&#160;&#160;&#160; #TC_OBJ_FORMAT = win64<br />行5&#160;&#160;&#160; #edit by gocool, if the x64 system need the nasm.exe use the x64 format parameters for executing.<br />行6&#160;&#160;&#160; #abort the x64 system here for building.<br />行7&#160;&#160;&#160; #2009/12/23<br />行8&#160;&#160;&#160; TC_OBJ_FORMAT = win32<br />行9&#160;&#160;&#160; TC_ARCH = x86<br />行10&#160;&#160;&#160; !endif<br />行11&#160;&#160;&#160; <br />行12&#160;&#160;&#160; "$(OBJ_PATH)\$(O)\Aes_$(TC_ARCH).obj": Aes_$(TC_ARCH).asm<br />行13&#160;&#160;&#160; &#160;&#160;&#160; nasm.exe -Xvc -f $(TC_OBJ_FORMAT) -Ox -D DLL_EXPORT -o "$@" -l "$(OBJ_PATH)\$(O)\Aes_$(TC_ARCH).lst" Aes_$(TC_ARCH).asm<br /></div>其中，为了减少变化量，也利于以后恢复，第4-7行为注释，第8、9行我将非x86的情况也定义成x86的情况，这样无论如何下面第13行的语句都将执行以x86体系为结构的设置，而这样的设置通常是正确的。<br /></li><li>fatal error LNK1000: Internal error during IncrBuildImage<br />据说是Microsoft Visual Studio 2008的一个BUG。http://blog.csdn.net/just_one_two/archive/2009/10/05/4634391.aspx<br />听说有两种方法，一种是方法1，需要下载补丁，我没有尝试。第二种通过修改配置的方法我成功了，步骤如下：<br />方法：项目->属性->链接器->常规&#160;&#160; 下面的&#8220;启用增量链接&#8221;，将&#8220;是(/INCREMENTAL)&#8221;改为&#8220;否(/INCREMENTAL:NO)&#8221;。<br />不过这又引入了另外一个警告：3>FormatCom.obj : warning LNK4075: 忽略&#8220;/EDITANDCONTINUE&#8221;(由于&#8220;/INCREMENTAL:NO&#8221;规范)<br />选择项目,属性->配置属性->C/C++，修改&#8220;调试信息格式&#8221;为&#8220;程序数据库(/Zi)&#8221;即可。<br /></li><li>警告：未找到下列环境变量<br /><div class="gc-code">4>项目 : warning PRJ0018 : 未找到下列环境变量:<br />4>$(PKCS11_INC)<br /></div>由于项目属性里设置有附加包含目录&#8220;$(PKCS11_INC)&#8221;，因此编译的时候会在系统变量里寻找PKCS11_INC项目，如果找不到，则给出警告，因此，我们需要手动补充这个项。方法同步骤5，增加一个变量为PKCS11_INC，值：D:\TrueCrypt\Common，其中，值就是之前我们拷贝三个文件（pkcs11.h、pkcs11f.h、pkcs11t.h）的目录。<br /></li><li>如果不出意外的话，你可能还会得到一个使用了PKEY_AppUserModel_ID未定义的声明符的错误。这个是用于标识用户态应用程序的唯一标识。你可以在Setup.h文件中定义：<div class="gc-code">/*---region add by gc---*/<br />#include "wtypes.h"<br />&#160;&#160;&#160; const PROPERTYKEY PKEY_AppUserModel_ID = {<br />&#160;&#160;&#160; &#160;&#160;&#160; {<br />&#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; (unsigned long)2009,/*unsigned long&#160; Data1;*/<br />&#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; (unsigned short)12,/*unsigned short Data2;*/<br />&#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; (unsigned short)23,/*unsigned short Data3;*/<br />&#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; 0x44,0x55,0x55,0x55,0x55,0x55,0x55,0x55<br />&#160;&#160;&#160; &#160;&#160;&#160; },/*GUID fmtid;*/<br />&#160;&#160;&#160; &#160;&#160;&#160; (DWORD)PID_FIRST_USABLE /*DWORD pid;*/<br />&#160;&#160;&#160; };<br />/*---endregion---*/<br /></div>其中，这个结构体是由GUID和PID共同组成的。<br /></li></ol></li></ol><h3>下载链接</h3><li>TrueCrypt下载：http://www.sfr-fresh.com/windows/misc/TrueCrypt-6.2a-Source.zip:a/Boot/Windows/Makefile</li><li>WinDDK下载：http://www.microsoft.com/whdc/DevTools/WDK/WDKpkg.mspx</li><li>PKCS11下载：http://svn.openvpn.net/projects/openvpn/test/time/openvpn/pkcs11-headers/</li><li>GZip下载：http://www.gzip.org/ 或者 http://www.gzip.org/gz124src.zip</li><li>Nasm下载：http://www.nasm.us/pub/nasm/releasebuilds/2.07/win32/</li><li>MSVC1.52下载：http://download.csdn.net/source/620960 （15.02MB）（似乎网上很多人都在找1.52（最后一个可以编译16bit程序的VC编译器），但官方网站上没有公开下载的链接，实在非常郁闷，我从MSDN订阅下载（收费的噢，杯具）则有67.6MB），如果大家实在找不到下载或者15.02MB的不可用，可以联系我。</li><br /><h3>参考链接</h3><ul><li>http://blog.csdn.net/skyremember/archive/2009/09/17/4562090.aspx</li><li>http://blog.sina.com.cn/s/blog_4758691d0100d8mc.html</li><li>http://lll332.blog.163.com/blog/static/1553692220093404635752/</li><li>http://msdn.microsoft.com/en-us/library/aa373931%28VS.85%29.aspx</li><li>http://hi.baidu.com/hhacker/blog/item/2fc5b3fb0b24132a4f4aea1d.html</li><li>http://blog.csdn.net/just_one_two/archive/2009/10/05/4634391.aspx</li><li>http://blog.csdn.net/liufei_learning/archive/2009/12/21/5047632.aspx</li><li>http://msdn.microsoft.com/zh-cn/library/958x11bc%28VS.80%29.aspx</li><li>http://bbs.xiakexing.com/cgi-bin/topic.cgi?forum=22&topic=498</li></ul><img src ="http://www.cppblog.com/mymsdn/aggbug/103863.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2009-12-23 23:47 <a href="http://www.cppblog.com/mymsdn/archive/2009/12/23/how-to-complie-TrueCrypt-63a.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>QuickSort快速排序法(2009-10-28)</title><link>http://www.cppblog.com/mymsdn/archive/2009/10/28/quicksort20091028.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Tue, 27 Oct 2009 16:38:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2009/10/28/quicksort20091028.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/99624.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2009/10/28/quicksort20091028.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/99624.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/99624.html</trackback:ping><description><![CDATA[<p>在本博客，之前有一个版本的QuickSort，其实网友很早就提出了相关的BUG，但是我一直没有时间进行修正，今天又有朋友提出了这个BUG，我刚好抽空看了一下，看来自己是相当不严谨以至于犯下了如此大错。</p> <p>原文链接：<a href="http://www.cppblog.com/mymsdn/archive/2009/03/06/quicksort.aspx">http://www.cppblog.com/mymsdn/archive/2009/03/06/quicksort.aspx</a> （未修复）</p> <p>关于修复BUG后的代码，将在本文中提供，原文中不进行修改，但会有提示指明是错误的，有兴趣的朋友也可以直接在原文的代码中寻找错误来锻炼自己排错的能力。</p> <p>下面就是几段代码：</p> <p>Algorithms.cpp</p><pre class="gc-code"><span style="color: blue">#include </span><span style="color: #a31515">"StdAfx.h"
</span><span style="color: blue">#include </span><span style="color: #a31515">"Algorithms.h"
</span>Algorithms::Algorithms(<span style="color: blue">void</span>)
{
}

Algorithms::~Algorithms(<span style="color: blue">void</span>)
{
}
</pre>
<p>Algorithms.h</p><pre class="gc-code"><span style="color: blue">#pragma once

#include </span><span style="color: #a31515">&lt;iostream&gt;

</span><span style="color: blue">class </span>Algorithms
{
<span style="color: blue">public</span>:
    Algorithms(<span style="color: blue">void</span>);
    ~Algorithms(<span style="color: blue">void</span>);

<span style="color: blue">public</span>:
    <span style="color: blue">template </span>&lt;<span style="color: blue">typename </span>T&gt;
    <span style="color: blue">static void </span>QuickSort(T* arr, size_t min, size_t max);
<span style="color: blue">private</span>:
    <span style="color: blue">template </span>&lt;<span style="color: blue">typename </span>T&gt;
    <span style="color: blue">static </span>size_t qsort_helper_partition(T* arr, size_t min, size_t max);
    <span style="color: blue">template </span>&lt;<span style="color: blue">typename </span>T&gt;
    <span style="color: blue">static inline void </span>swap(T* arr, size_t x, size_t y);
    <span style="color: green">// helper
    </span><span style="color: blue">template </span>&lt;<span style="color: blue">typename </span>T&gt;
    <span style="color: blue">static inline void </span>helper_show_all(T* arr, size_t min, size_t max, <span style="color: blue">char </span>*msg);
};

<span style="color: blue">template </span>&lt;<span style="color: blue">typename </span>T&gt;
<span style="color: blue">void </span>Algorithms::QuickSort(T* arr, size_t min, size_t max)
{
    <span style="color: blue">if</span>(min &gt;= max || max == 0 - 1) <span style="color: blue">return</span>;
    helper_show_all(arr, min, max, <span style="color: #a31515">"before qsort_helper_partition"</span>);
    size_t p = qsort_helper_partition(arr, min, max);
    helper_show_all(arr, min, max, <span style="color: #a31515">"after qsort_helper_partition"</span>);

    QuickSort(arr, min, p - 1);
    QuickSort(arr, p + 1, max);
}
<span style="color: green">/*
*    @BUG:    bug200910280001
*    @DESC:    由于在循环while(true)中，假设原代码
            01    while(true)
            02    {
            03        while(cmp &lt; arr[i])
            04            ++i;
            05        while(arr[j] &lt; cmp)
            06            --j;
            07        if(i &gt;= j) break;
            08
            09        swap(arr, i, j);
            10    }
            中，前两段（行号，行号）中的代码均返回false，
            则无法进入++i或者--j，那么在这个while(true)中，
            i和j的值将无法发生变化，从而导致死循环。
    @LINK:http://www.cppblog.com/mymsdn/archive/2009/03/06/quicksort.aspx#99606
*/
</span><span style="color: blue">template </span>&lt;<span style="color: blue">typename </span>T&gt;
size_t Algorithms::qsort_helper_partition(T* arr, size_t min, size_t max)
{
    T cmp = arr[min];
    <span style="color: blue">int </span>i = min, j = max; <span style="color: green">// bug200910280001:修正i = min+1，将+1的动作放在循环内。
    </span><span style="color: blue">while</span>(<span style="color: blue">true</span>)
    {
        <span style="color: blue">while</span>(cmp &lt; arr[++i]) <span style="color: green">// bug200910280001:将原本在循环外的min+1，移进循环内，并首先+1
            </span>; <span style="color: green">// bug200910280001:将++1移至while条件中。
        </span><span style="color: blue">while</span>(arr[j] &lt; cmp)
            --j;
        <span style="color: blue">if</span>(i &gt;= j) <span style="color: blue">break</span>;

        helper_show_all(arr, min, max, <span style="color: #a31515">"before swap(arr, i, j)"</span>);
        swap(arr, i, j);
        helper_show_all(arr, min, max, <span style="color: #a31515">"after swap(arr, i, j)"</span>);
    }
    swap(arr, min, j);
    <span style="color: blue">return </span>j;
}

<span style="color: blue">template </span>&lt;<span style="color: blue">typename </span>T&gt;
<span style="color: blue">void </span>Algorithms::swap(T* arr, size_t x, size_t y)
{
    T tmp = arr[x];
    arr[x] = arr[y];
    arr[y] = tmp;
}

<span style="color: blue">template </span>&lt;<span style="color: blue">typename </span>T&gt;
<span style="color: blue">void </span>Algorithms::helper_show_all(T* arr, size_t min, size_t max, <span style="color: blue">char </span>*msg)
{
    std::cout &lt;&lt; <span style="color: #a31515">"current array :\t"</span>;
    <span style="color: blue">for</span>(<span style="color: blue">int </span>i = min; i &lt; max; ++i)
    {
        std::cout &lt;&lt; arr[i] &lt;&lt; <span style="color: #a31515">" "</span>;
    }
    std::cout&lt;&lt;<span style="color: #a31515">"\t//"</span>&lt;&lt;msg;
    std::cout&lt;&lt;std::endl;
}</pre>
<p>cpp_quickSort.cpp</p><pre class="gc-code"><span style="color: green">// cpp_quickSort.cpp : 定义控制台应用程序的入口点。
//

</span><span style="color: blue">#include </span><span style="color: #a31515">"stdafx.h"
</span><span style="color: blue">#include </span><span style="color: #a31515">"Algorithms.h"
</span><span style="color: blue">#include </span><span style="color: #a31515">&lt;iostream&gt;
</span><span style="color: blue">#include </span><span style="color: #a31515">&lt;vector&gt;
</span><span style="color: blue">#include </span><span style="color: #a31515">&lt;algorithm&gt;

</span><span style="color: blue">int </span>_tmain(<span style="color: blue">int </span>argc, _TCHAR* argv[])
{
    <span style="color: blue">int </span>arr_begin = 0;
    <span style="color: blue">int </span>arr_length = 12; <span style="color: green">//The length will instead of the magic numbers 
    </span><span style="color: blue">int </span>arr[] = {8, 3, 7, 1, 5, 6, 2, 1, 9, 9, 1, 1};
    
    <span style="color: green">// Test for : 20091028bug0001
    // int arr[] = {1, 1, 1};

    </span>std::cout &lt;&lt; <span style="color: #a31515">"input array :\t"</span>;
    <span style="color: blue">for</span>(size_t i = arr_begin; i != arr_length; ++i)
    {
        std::cout&lt;&lt;arr[i]&lt;&lt;<span style="color: #a31515">" "</span>;
    }
    std::cout&lt;&lt;std::endl;

    Algorithms::QuickSort(arr, arr_begin, arr_length);

    std::cout &lt;&lt; <span style="color: #a31515">"result array :\t"</span>;
    <span style="color: blue">for</span>(size_t i = arr_begin; i != arr_length; ++i)
    {
        std::cout&lt;&lt;arr[i]&lt;&lt;<span style="color: #a31515">" "</span>;
    }
    std::cout&lt;&lt;std::endl;

    std::cout &lt;&lt; <span style="color: #a31515">"--------------------" </span>&lt;&lt; std::endl;
    std::cout &lt;&lt; <span style="color: #a31515">"input array :\t"</span>;

    std::vector&lt;<span style="color: blue">int</span>&gt; vec;
    vec.push_back(3);
    vec.push_back(1);
    vec.push_back(4);
    vec.push_back(1);
    vec.push_back(7);
    vec.push_back(6);

    <span style="color: blue">for</span>(std::vector&lt;<span style="color: blue">int</span>&gt;::iterator iter = vec.begin();
        iter != vec.end(); ++ iter)
    {
        std::cout&lt;&lt;*iter&lt;&lt;<span style="color: #a31515">" "</span>;
    }
    std::cout&lt;&lt;std::endl;

    std::sort(vec.begin(), vec.end());

    <span style="color: blue">for</span>(std::vector&lt;<span style="color: blue">int</span>&gt;::iterator iter = vec.begin();
        iter != vec.end(); ++ iter)
    {
        std::cout&lt;&lt;*iter&lt;&lt;<span style="color: #a31515">" "</span>;
    }
    std::cout&lt;&lt;std::endl;

    <span style="color: blue">return </span>0;
}

</pre><img src ="http://www.cppblog.com/mymsdn/aggbug/99624.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2009-10-28 00:38 <a href="http://www.cppblog.com/mymsdn/archive/2009/10/28/quicksort20091028.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于NULL在C和C++中的区别</title><link>http://www.cppblog.com/mymsdn/archive/2009/05/31/about-the-NULL-in-C-or-CPlusPlus.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Sun, 31 May 2009 12:50:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2009/05/31/about-the-NULL-in-C-or-CPlusPlus.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/86308.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2009/05/31/about-the-NULL-in-C-or-CPlusPlus.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/86308.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/86308.html</trackback:ping><description><![CDATA[这个问题源自对'\0'，0，以及NULL的探究！<br>先看看标题所提到的内容：<br>根据https://research.microsoft.com/en-us/um/redmond/projects/invisible/include/__defs.h.htm文档中的定义：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">#if</span><span style="color: #000000;">&nbsp;!defined(NULL)&nbsp;&amp;&amp;&nbsp;defined(__NEEDS_NULL)</span><span style="color: #000000;"><br>#ifdef&nbsp;__cplusplus<br></span><span style="color: #0000ff;">#define</span><span style="color: #000000;">&nbsp;NULL&nbsp;&nbsp;&nbsp;&nbsp;0</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">#else</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">#define</span><span style="color: #000000;">&nbsp;NULL&nbsp;&nbsp;&nbsp;&nbsp;((void&nbsp;*)0)</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">#endif</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">#endif</span><span style="color: #000000;"><br></span></div>
在C和C++中，分别是由(void*)0和0来表示的。<br>而'\0'是ASCII中的值，ASCII中它的值就是0。<br>所以它们三者是相同的。<br><br>参考资料：<br>https://research.microsoft.com/en-us/um/redmond/projects/invisible/include/__defs.h.htm<br><br>在探究的过程中找到下面的一个帖子。很是不错，COPY如下。<br>转载自：http://blog.chinaunix.net/u/18517/showart_309917.html<br><br>
<div>
<hr id="null">
</div>
<div>&nbsp;&nbsp;&nbsp; 本文转自：<a href="http://bbs.chinaunix.net/viewthread.php?tid=544415&amp;extra=&amp;page=7">http://bbs.chinaunix.net/viewthread.php?tid=544415&amp;extra=&amp;page=7</a></div>
<div>&nbsp;&nbsp;&nbsp;
帖子里讨论了C语言中的空指针、空指针常量、NULL、0等概念及相互关系及区别。这里摘录whyglinux兄的总结。做个标签，呵呵^_^</div>
<div>
<hr id="null">
</div>
<ol>
    <li>什么是空指针常量（null pointer constant）?<br><br>[6.3.2.3-3] An integer constant
    expression with the value 0, or such an expression cast to type void *, is
    called a null pointer constant.<br><br>这里告诉我们：0、0L、'\0'、3 - 3、0 * 17
    （它们都是&#8220;integer constant expression&#8221;）以及 (void*)0 （<font color="#990033">tyc：
    我觉得(void*)0应该算是一个空指针吧，更恰当一点</font>）等都是空指针常量（注意 (char*) 0 不叫空指针常量，只是一个空指针值）。<font color="#0000ff">至于系统选取哪种形式作为空指针常量使用，则是实现相关的</font>。一般的 C 系统选择 (void*)0 或者 0
    的居多（也有个别的选择 0L）；至于 C++ 系统，由于存在严格的类型转化的要求，void* 不能象 C 中那样自由转换为其它指针类型，所以通常选 0
    作为空指针常量（<font color="#990033">tyc: C++标准推荐</font>），而不选择 (void*)0。<br><br>
    </li>
    <li>什么是空指针（null pointer）?<br><br>[6.3.2.3-3] If a null pointer constant is
    converted to a pointer type, the resulting pointer, called a null pointer, is
    guaranteed to compare unequal to a pointer to any object or
    function.<br><br>因此，如果 p 是一个指针变量，则 p = 0;、p = 0L;、p = '\0';、p = 3 - 3;、p = 0 *
    17; 中的任何一种赋值操作之后（对于 C 来说还可以是 p = (void*)0;）， p 都成为一个空指针，<font color="#0000ff">由系统保证空指针不指向任何实际的对象或者函数</font>。反过来说，任何对象或者函数的地址都不可能是空指针。（<font color="#990033">tyc: 比如这里的(void*)0就是一个空指针。把它理解为null pointer还是null pointer
    constant会有微秒的不同，当然也不是紧要了</font>）<br><br>
    </li>
    <li>什么是 NULL？<br><br>[6.3.2.3-Footnote] The macro NULL is defined in
    &lt;stddef.h&gt; (and other headers) as a null pointer constant<br><br><font color="#0000ff">即 NULL 是一个标准规定的宏定义，用来表示空指针常量</font>。因此，除了上面的各种赋值方式之外，还可以用 p =
    NULL; 来使 p 成为一个空指针。（<font color="#990033">tyc：很多系统中的实现：#define NULL
    (void*)0，与这里的&#8220;a null pointer constant&#8221;并不是完全一致的</font>）<br><br>
    </li>
    <li>空指针（null
    pointer）指向了内存的什么地方（空指针的内部实现）？<br><br>标准并没有对空指针指向内存中的什么地方这一个问题作出规定，也就是说用哪个具体的地址值（0x0
    地址还是某一特定地址）表示空指针取决于系统的实现。我们常见的空指针一般指向 0 地址，即空指针的内部用全 0 来表示（zero null
    pointer，零空指针）；也有一些系统用一些特殊的地址值或者特殊的方式表示空指针（nonzero null pointer，非零空指针），具体请参见<a href="http://c-faq.com/null/machexamp.html" target="_blank"><font color="#800080">C
    FAQ</font></a>。<br><br>幸运的是，在实际编程中不需要了解在我们的系统上空指针到底是一个 zero null pointer 还是
    nonzero null pointer，<font color="#0000ff">我们只需要了解一个指针是否是空指针就可以了——编译器会自动实现其中的转换，为我们屏蔽其中的实现细节。</font>注意：不要把空指针的内部表示等同于整数
    0 的对象表示——如上所述，有时它们是不同的。<br><br>
    </li>
    <li><font color="#0000ff">如何判断一个指针是否是一个空指针？</font><br><br>这可以通过与空指针常量或者其它的空指针的比较来实现（注意与空指针的内部表示无关）。例如，假设
    p 是一个指针变量，q 是一个同类型的空指针，要检查 p
    是否是一个空指针，可以采用下列任意形式之一——它们在实现的功能上都是等价的，所不同的只是风格的差别。<br><br>指针变量 p
    是空指针的判断：<br><font color="#0000ff">if ( p == 0 )<br></font>if ( p == '\0' )<br>if (
    p == 3 - 3 )<br><font color="#0000ff">if ( p == NULL )</font>&nbsp;&nbsp;/* 使用 NULL
    必须包含相应的标准库的头文件 */<br>if ( NULL == p )<br>if ( !p )<br>if ( p == q
    )<br>...<br><br>指针变量 p 不是空指针的判断：<br>if ( p != 0 )<br>if ( p != '\0' )<br>if ( p
    != 3 - 3 )<br>if ( p != NULL )&nbsp;&nbsp;/* 使用 NULL 必须包含相应的标准库的头文件 */<br>if ( NULL != p
    )<br>if ( p )<br>if ( p != q )<br>...<br><br>
    </li>
    <li>可以用 memset 函数来得到一个空指针吗？<br><br>这个问题等同于：如果 p 是一个指针变量，那么<br><br>memset(
    &amp;p, 0, sizeof(p) ); 和 p =
    0;<br><br>是等价的吗？<br><br>答案是否定的，虽然在大多数系统上是等价的，但是因为有的系统存在着&#8220;非零空指针&#8221; （nonzero null
    pointer），所以这时两者不等价。由于这个原因，要注意当想将指针设置为空指针的时候不应该使用
    memset，而应该用空指针常量或空指针对指针变量赋值或者初始化的方法。<br><br>
    </li>
    <li>可以定义自己的 NULL 的实现吗？兼答"NULL 的值可以是 1、2、3 等值吗？"类似问题<br><br>[7.1.3-2] If the
    program declares or defines an identifier in a context in which it is reserved
    (other than as allowed by 7.1.4), or defines a reserved identifier as a macro
    name, the behavior is undefined.<br><br>NULL 是标准库中的一个符合上述条件的 reserved identifier
    （保留标识符）。所以，如果包含了相应的标准头文件而引入了 NULL 的话，则再在程序中重新定义 NULL
    为不同的内容是非法的，其行为是未定义的。也就是说，如果是符合标准的程序，其 NULL 的值只能是 0，不可能是除 0 之外的其它值，比如 1、2、3
    等。<br><br>
    </li>
    <li>malloc 函数在分配内存失败时返回 0 还是 NULL？<br><br>malloc 函数是标准 C
    规定的库函数。在标准中明确规定了在其内存分配失败时返回的是一个 &#8220;null pointer&#8221;（空指针）：<br><br>[7.20.3-1] If the
    space cannot be allocated, a null pointer is returned.<br><br>对于空指针值，一般的文档（比如
    man）中倾向于用 NULL 表示，而没有直接说成 0。但是我们应该清楚：对于指针类型来说，返回 NULL 和 返回 0 是完全等价的，因为 NULL 和 0
    都表示 &#8220;null pointer&#8221;（空指针）。（<font color="#990033">tyc：一般系统中手册中都返回NULL，那我们就用NULL吧</font>）</li>
</ol>
<p>另外，附C FAQ上关于null pointer的解释：<a href="http://c-faq.com/null/index.html" target="_blank"><font color="#800080">C FAQ：null pointer</font></a></p>
<br>   <img src ="http://www.cppblog.com/mymsdn/aggbug/86308.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2009-05-31 20:50 <a href="http://www.cppblog.com/mymsdn/archive/2009/05/31/about-the-NULL-in-C-or-CPlusPlus.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何查看你可以分配多大内存</title><link>http://www.cppblog.com/mymsdn/archive/2009/05/25/85667.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Sun, 24 May 2009 17:37:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2009/05/25/85667.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/85667.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2009/05/25/85667.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/85667.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/85667.html</trackback:ping><description><![CDATA[<pre class="gc-code"><span style="color: #7f0055">#include </span><span style="color: #2a00ff">&lt;stdio.h&gt;
</span><span style="color: #7f0055">#include </span><span style="color: #2a00ff">&lt;stdlib.h&gt;

</span><span style="color: #7f0055">int </span>main(<span style="color: #7f0055">void</span>){
    <span style="color: #7f0055">int </span>MB = 0;
    <span style="color: #7f0055">while</span>(<span style="color: #642880">malloc</span>(1 &lt;&lt; 20))
        ++MB;
    <span style="color: #642880">printf</span>(<span style="color: #2a00ff">"Allocated %d MB total\n"</span>, MB);

    <span style="color: #7f0055">return </span>EXIT_SUCCESS;
}</pre>
<p>原理，因为2的20次方就是1MB（2的10次方为1KB，2的30次方为1GB，以此类推）。</p>
<p>如果你请求分配的内存块小于1MB，你得到的内存是否比这要多一些呢？为什么？</p>
<p>答：</p>
<p>这不是绝对的！</p>
<p>在本例中使用</p>
<p>1&lt;&lt;22（4MB）得到的结果乘4是2000MB</p>
<p>1&lt;&lt;21（2MB）得到的结果乘2是1972MB</p>
<p>1&lt;&lt;20（1MB）得到的结果是1918MB</p>
<p>1&lt;&lt;19（0.5MB）得到的结果除2是1812MB</p>
<p>1&lt;&lt;18（0.25MB）得到的结果除4是2003MB</p>
<p>1&lt;&lt;17（0.125MB）得到的结果除8是2034MB</p>
<p>显然出现了一个意外的结果。</p><img src ="http://www.cppblog.com/mymsdn/aggbug/85667.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2009-05-25 01:37 <a href="http://www.cppblog.com/mymsdn/archive/2009/05/25/85667.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>static in C</title><link>http://www.cppblog.com/mymsdn/archive/2009/05/24/85626.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Sun, 24 May 2009 10:17:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2009/05/24/85626.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/85626.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2009/05/24/85626.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/85626.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/85626.html</trackback:ping><description><![CDATA[<!--MyMSDN style!--><link rel="stylesheet" type="text/css" href="http://files.cnblogs.com/volnet/gocool.css"> <style type="text/css">
body{background-color:#eeeeee;}
</style>  <p></p><pre class="gc-code"><span style="color: #7f0055">#include </span><span style="color: #2a00ff">&lt;stdio.h&gt;
</span><span style="color: #7f0055">#include </span><span style="color: #2a00ff">&lt;stdlib.h&gt;

</span><span style="color: #7f0055">char </span>* favorite_fruit1(<span style="color: #7f0055">void</span>);
<span style="color: #7f0055">char </span>* favorite_fruit2(<span style="color: #7f0055">void</span>);
<span style="color: #7f0055">void </span>favorite_fruit3(<span style="color: #7f0055">char </span>**);
<span style="color: #7f0055">int </span>main(<span style="color: #7f0055">void</span>) {
    <span style="color: #7f0055">char </span>* fruit1 = favorite_fruit1();
    <span style="color: #642880">printf</span>(<span style="color: #2a00ff">"%s\n"</span>, fruit1);

    <span style="color: #7f0055">char </span>* fruit2 = favorite_fruit2();
    <span style="color: #642880">printf</span>(<span style="color: #2a00ff">"%s\n"</span>, fruit2);

    <span style="color: #7f0055">char </span>* fruit3 = NULL;
    favorite_fruit3(&amp;fruit3);
    <span style="color: #642880">printf</span>(<span style="color: #2a00ff">"%s\n"</span>, fruit3);

    <span style="color: #642880">printf</span>(<span style="color: #2a00ff">"------END of CODE------"</span>);
    <span style="color: #7f0055">return </span>EXIT_SUCCESS;
}
<span style="color: #7f0055">char </span>* favorite_fruit1(<span style="color: #7f0055">void</span>){
    <span style="color: #7f0055">char </span>deciduous[] = <span style="color: #2a00ff">"apple"</span>;
    <span style="color: #7f0055">return </span>deciduous;
}
<span style="color: #7f0055">char </span>* favorite_fruit2(<span style="color: #7f0055">void</span>){
    <span style="color: #7f0055">static char </span>deciduous[] = <span style="color: #2a00ff">"apple"</span>;
    <span style="color: #7f0055">return </span>deciduous;
}
<span style="color: #7f0055">void </span>favorite_fruit3(<span style="color: #7f0055">char </span>** fruit){
    <span style="color: #7f0055">static char </span>deciduous[] = <span style="color: #2a00ff">"apple"</span>;
    *fruit = deciduous;
}</pre>
<p>favorite_fruit1很明显会出现问题，原因是因为<span style="color: #7f0055">char </span>deciduous[]是局部变量，在函数调用返回后，就释放了。</p>
<p>favorite_fruit2因为使用了static，而static限定了变量被保存在数据段（data segment）中，它的声明周期同程序一样长。所以不会出错。</p>
<p>favorite_fruit3是另一种有效的写法，其原理同2。</p> <img src ="http://www.cppblog.com/mymsdn/aggbug/85626.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2009-05-24 18:17 <a href="http://www.cppblog.com/mymsdn/archive/2009/05/24/85626.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[C专家编程]学习笔记——a.out，段(segment)，查看可执行文件中的段</title><link>http://www.cppblog.com/mymsdn/archive/2009/05/19/expert-c-programming-a-out-segment.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Tue, 19 May 2009 15:50:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2009/05/19/expert-c-programming-a-out-segment.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/83424.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2009/05/19/expert-c-programming-a-out-segment.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/83424.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/83424.html</trackback:ping><description><![CDATA[本部分内容详见《C专家编程》P119<br>查看可执行文件中的段<br>1.编译&#8220;hello world&#8221;程序，在可执行文件中执行ls -l，得到文件的总体大小。运行size得到文件里各个段的大小。<br>2.增加一个全局的int[1000]数组声明，重新进行编译，再用上面的命令得到总体及各个段的大小，注意前后的区别。<br>3.现在，在数组的声明中增加初始值（记住，C语言并不强迫对数组进行初始化时为每个元素提供初始值）。这将使数组从BSS段转换到数据段。重复上面的测量，注意各个段前后大小的区别。<br>4.现在，在函数内声明一个巨大的数组。然后再声明一个巨大的局部数组，但这次加上初始值。重复上面的测量。定义于函数内部的局部数组存储在可执行文件中吗？有没有初始化有什么不同吗？<br>5.如果在调试状态下编译，文件和段的大小有没有变化？是为了最大程度的优化吗？<br>分析上面&#8220;编程挑战&#8221;的结果，使自己确信：<br>
<ul>
    <li>数据段保存在目标文件中。</li>
    <li>BSS段不保存在目标文件中（除了记录BSS段在运行时所需要的大小）。</li>
    <li>文本段是最容易受优化措施影响的段。</li>
    <li>a.out文件的大小受调试状态下编译的影响，但段不受影响。</li>
</ul>
helloworld.c的文件最终如下：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">stdio.h</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;global_array[</span><span style="color: #000000;">1000</span><span style="color: #000000;">]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;{</span><span style="color: #000000;">100</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">101</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">102</span><span style="color: #000000;">};<br></span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;SayGoodBye(</span><span style="color: #0000ff;">void</span><span style="color: #000000;">);<br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;main(</span><span style="color: #0000ff;">void</span><span style="color: #000000;">)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000;">"</span><span style="color: #000000;">hello&nbsp;Linux&nbsp;world</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;main_array[</span><span style="color: #000000;">1000</span><span style="color: #000000;">]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;{</span><span style="color: #000000;">10</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">20</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">30</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">40</span><span style="color: #000000;">};<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SayGoodBye();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>}<br><br></span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;SayGoodBye(</span><span style="color: #0000ff;">void</span><span style="color: #000000;">)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;goodbye_array[</span><span style="color: #000000;">1000</span><span style="color: #000000;">]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;{</span><span style="color: #000000;">1024</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">2048</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">4096</span><span style="color: #000000;">};<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000;">"</span><span style="color: #000000;">good&nbsp;bye&nbsp;user!</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>}<br></span></div>
<br>以下命令按照文中步骤依次修改上文代码（过程不赘述），运行size后的数据如下所示：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">[volnet@GoCool&nbsp;c]$&nbsp;echo&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">size&nbsp;helloworld1</span><span style="color: #000000;">"</span><span style="color: #000000;">;&nbsp;size&nbsp;helloworld1;&nbsp;echo&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">size&nbsp;helloworld2</span><span style="color: #000000;">"</span><span style="color: #000000;">;&nbsp;size&nbsp;helloworld2;&nbsp;echo&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">size&nbsp;helloworld3</span><span style="color: #000000;">"</span><span style="color: #000000;">;&nbsp;size&nbsp;helloworld3;&nbsp;echo&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">size&nbsp;helloworld4</span><span style="color: #000000;">"</span><span style="color: #000000;">;&nbsp;size&nbsp;helloworld4;<br>size&nbsp;helloworld1<br>&nbsp;&nbsp;&nbsp;text&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bss&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dec&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hex&nbsp;&nbsp;&nbsp;&nbsp;filename<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">1015</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">252</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">8</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">1275</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4fb&nbsp;&nbsp;&nbsp;&nbsp;helloworld1<br>size&nbsp;helloworld2<br>&nbsp;&nbsp;&nbsp;text&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bss&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dec&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hex&nbsp;&nbsp;&nbsp;&nbsp;filename<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">1015</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">252</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">4032</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">5299</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14b3&nbsp;&nbsp;&nbsp;&nbsp;helloworld2<br>size&nbsp;helloworld3<br>&nbsp;&nbsp;&nbsp;text&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bss&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dec&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hex&nbsp;&nbsp;&nbsp;&nbsp;filename<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">1015</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">4280</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">8</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">5303</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14b7&nbsp;&nbsp;&nbsp;&nbsp;helloworld3<br>size&nbsp;helloworld4<br>&nbsp;&nbsp;&nbsp;text&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bss&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dec&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hex&nbsp;&nbsp;&nbsp;&nbsp;filename<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">1270</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">4280</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">8</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">5558</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;15b6&nbsp;&nbsp;&nbsp;&nbsp;helloworld4<br></span></div>
<br>注：<br>BSS的全称是：Block Started by Symbol（由符号开始的块），它是旧式IBM704汇编程序的一个伪指令，UNIX借用了这个名字，至今依然沿用。<br> <img src ="http://www.cppblog.com/mymsdn/aggbug/83424.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2009-05-19 23:50 <a href="http://www.cppblog.com/mymsdn/archive/2009/05/19/expert-c-programming-a-out-segment.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Expert C Programming notes</title><link>http://www.cppblog.com/mymsdn/archive/2009/04/01/78518.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Tue, 31 Mar 2009 16:31:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2009/04/01/78518.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/78518.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2009/04/01/78518.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/78518.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/78518.html</trackback:ping><description><![CDATA[<p>1、const其实并不是真正的常量（P32）</p> <p><a href="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/ExpertCProgrammingnotes_14216/const_is_not_constant_2.gif"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="const_is_not_constant" border="0" alt="const_is_not_constant" src="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/ExpertCProgrammingnotes_14216/const_is_not_constant_thumb.gif" width="389" height="545"></a></p> <p>2、早期的gets()中的Bug导致了Internet蠕虫（P42）</p> <p>gets()函数并不检查缓冲区的空间，事实上它也无法检查缓冲区的空间。如果函数的调用者提供了一个指向堆栈的指针，并且gets()函数读入的字符数量超过缓冲区的空间，gets()函数将会愉快地将多出来的字符继续写入到堆栈中，这就覆盖了堆栈原先的内容。——这就是病毒利用它来写入额外空间，并引发蠕虫病毒的前提。</p> <p>推荐的方式是将</p> <p>gets(line)</p> <p>替换为</p> <p>if(fgets(line, sizeof(line), stdin) == NULL)</p> <blockquote> <p>exit(1);</p></blockquote> <p>3、相邻字符串常量自动连接（P45）</p> <p>这个其实已经应用很普遍了，但是我个人用的比较少，特此记录一下。</p> <p><a href="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/ExpertCProgrammingnotes_14216/ansi-c_connect_string_2.gif"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="ansi-c_connect_string" border="0" alt="ansi-c_connect_string" src="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/ExpertCProgrammingnotes_14216/ansi-c_connect_string_thumb.gif" width="645" height="329"></a> </p> <p>4、返回一个指针？（P48）</p> <p>这个话题围绕一个程序的BUG来展开，这个程序返回了局部变量的值的指针，这么说当然你一眼就能看得出来问题所在，但是在很多时候，这个错误却总是在你的眼皮子底下溜走。</p> <p>作者提供了五种方式，只能说可以用，但唯一推荐的只有一个，详见作者的分析（P48）（不是什么高深的理论，你自己也能分析地出来）。</p> <p>a.返回一个字符串常量的指针。因为常量存在静态数据存储区，所以指针没问题。</p> <p>b.使用全局声明的数组。提到全局两个字，就知道这个方法有很大的局限性。</p> <p>c.使用静态数组。下一次调用将覆盖这个数组内容。</p> <blockquote> <p>char * func() {</p> <p>static char buffer[20];</p> <p>…</p> <p>return buffer;</p> <p>}</p></blockquote> <p>d.显式分配一些内存，保存返回的值。</p> <blockquote> <p>char&nbsp; * func() {</p> <p>char * s = malloc(120);</p> <p>…</p> <p>return s;</p> <p>}</p></blockquote> <p>既然用到了malloc，就必然伴随着free，因此带来了内存管理的问题，增加了开发者负担。</p> <p>e.（<u>推荐</u>）在调用前后，由函数调用者分配内存，并由其释放，在同一地方释放对于内存管理来说代价相对最小。</p> <blockquote> <p>void func( char * result, int size) {</p></blockquote> <blockquote> <p>…</p> <p>strncpy(result, “That’d be in the data segment, Bob”, size);</p> <p>}</p></blockquote> <blockquote> <p>buffer = malloc(size);</p> <p>func(buffer, size);</p> <p>…</p> <p>free(buffer);</p></blockquote><img src ="http://www.cppblog.com/mymsdn/aggbug/78518.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2009-04-01 00:31 <a href="http://www.cppblog.com/mymsdn/archive/2009/04/01/78518.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>QuickSort快速排序法(2009-03-06)</title><link>http://www.cppblog.com/mymsdn/archive/2009/03/06/quicksort.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Thu, 05 Mar 2009 19:03:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2009/03/06/quicksort.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/75693.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2009/03/06/quicksort.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/75693.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/75693.html</trackback:ping><description><![CDATA[<script type="text/javascript" language="javascript">
var totalConfirmTime = 10;
var currentConfirmTime = 0;
var enableNoticeReader = true;
var enableCloseNotice = true;
function onRedirect20091028(){
	
	if(enableNoticeReader && currentConfirmTime < totalConfirmTime)
	{
	if(confirm("您已经在本页面逗留"+ 10*(++currentConfirmTime) +"秒，本页面代码存在BUG！\n是否确认跳转到正确代码页面《QuickSort快速排序法(2009-10-28)》？"))
	{
		window.location.href="http://www.cppblog.com/mymsdn/archive/2009/10/28/quicksort20091028.html?source=20090306&method=setTimeOut"
	}
	else
	{
		if(enableCloseNotice)
		{
			if(confirm("我们将最多提示您"+ totalConfirmTime +"次。\n如果您决定继续逗留在本页，是否需要关闭页面提醒？\n（点击“是”即可关闭！）"))
			{
				enableNoticeReader = false;
			}
			else
			{
				setTimeout(onRedirect20091028, 10000);
			}
			// only 1 time.
			enableCloseNotice = false;
		}
		else
		{
			setTimeout(onRedirect20091028, 10000);
		}
	}
	}
}
function closeEnableNoticeReader(){	enableNoticeReader = false;	}
setTimeout(onRedirect20091028, 10000);
</script> <div style="border-bottom: #000 1px solid; border-left: #000 1px solid; padding-bottom: 2px; background-color: yellow; padding-left: 20px; padding-right: 20px; color: red; border-top: #000 1px solid; font-weight: 700; border-right: #000 1px solid; padding-top: 2px"> <p>本文代码已经更新，修正严重BUG，最新版本详见《<a href="http://www.cppblog.com/mymsdn/archive/2009/10/28/quicksort20091028.html">QuickSort快速排序法(2009-10-28)</a>》！</p> <p>本文中所涉及的代码未做更新，请移步最新版查阅正确代码！</p> <p>链接：<a title="http://www.cppblog.com/mymsdn/archive/2009/10/28/quicksort20091028.html" href="http://www.cppblog.com/mymsdn/archive/2009/10/28/quicksort20091028.html">http://www.cppblog.com/mymsdn/archive/2009/10/28/quicksort20091028.html</a></p> <p><input onclick="closeEnableNoticeReader();" value="关闭页面提醒功能" type="button"> <p></p></div> <hr>  <p>快速排序法：（好土，感觉满世界都会，不过还是写一下，当然了，标准库里多的是排序算法），这里还是实现经典版的快速排序了，时间复杂度O(nlogn)</p> <p>Algorithms.h</p><pre class="gc-code" title="源代码有错，详见页面顶部说明！"><span style="color: blue">#pragma once

#include </span><span style="color: #a31515">&lt;iostream&gt;

</span><span style="color: blue">class </span>Algorithms
{
<span style="color: blue">public</span>:
    Algorithms(<span style="color: blue">void</span>);
    ~Algorithms(<span style="color: blue">void</span>);

<span style="color: blue">public</span>:
    <span style="color: blue">template </span>&lt;<span style="color: blue">typename </span>T&gt;
    <span style="color: blue">static void </span>QuickSort(T* arr, size_t min, size_t max);
<span style="color: blue">private</span>:
    <span style="color: blue">template </span>&lt;<span style="color: blue">typename </span>T&gt;
    <span style="color: blue">static </span>size_t qsort_helper_partition(T* arr, size_t min, size_t max);
    <span style="color: blue">template </span>&lt;<span style="color: blue">typename </span>T&gt;
    <span style="color: blue">static inline void </span>swap(T* arr, size_t x, size_t y);
};

<span style="color: blue">template </span>&lt;<span style="color: blue">typename </span>T&gt;
<span style="color: blue">void </span>Algorithms::QuickSort(T* arr, size_t min, size_t max)
{
    <span style="color: blue">if</span>(min &gt;= max || max == 0 - 1) <span style="color: blue">return</span>;
    size_t p = qsort_helper_partition(arr, min, max);

    QuickSort(arr, min, p - 1);
    QuickSort(arr, p + 1, max);
}

<span style="color: blue">template </span>&lt;<span style="color: blue">typename </span>T&gt;
size_t Algorithms::qsort_helper_partition(T* arr, size_t min, size_t max)
{
    T cmp = arr[min];
    <span style="color: blue">int </span>i = min + 1, j = max;
    <span style="color: blue">while</span>(<span style="color: blue">true</span>)
    {
        <span style="color: blue">while</span>(cmp &lt; arr[i])
            ++i;
        <span style="color: blue">while</span>(arr[j] &lt; cmp)
            --j;
        <span style="color: blue">if</span>(i &gt;= j) <span style="color: blue">break</span>;

        swap(arr, i, j);
    }
    swap(arr, min, j);
    <span style="color: blue">return </span>j;
}

<span style="color: blue">template </span>&lt;<span style="color: blue">typename </span>T&gt;
<span style="color: blue">void </span>Algorithms::swap(T* arr, size_t x, size_t y)
{
    T tmp = arr[x];
    arr[x] = arr[y];
    arr[y] = tmp;
}</pre>
<p>用法：（顺便有标准库的排序法，当然只是调一下，没有什么可说的了）<pre class="gc-code" title="源代码有错，详见页面顶部说明！"><span style="color: blue">#include </span><span style="color: #a31515">"Algorithms.h"
</span><span style="color: blue">#include </span><span style="color: #a31515">&lt;iostream&gt;
</span><span style="color: blue">#include </span><span style="color: #a31515">&lt;vector&gt;
</span><span style="color: blue">#include </span><span style="color: #a31515">&lt;algorithm&gt;

</span><span style="color: blue">int </span>_tmain(<span style="color: blue">int </span>argc, _TCHAR* argv[])
{
    <span style="color: blue">int </span>arr[] = {4, 8, 3, 7, 1, 5, 6, 2};

    <span style="color: blue">for</span>(size_t i = 0; i != 8; ++i)
    {
        std::cout&lt;&lt;arr[i]&lt;&lt;<span style="color: #a31515">" "</span>;
    }
    std::cout&lt;&lt;std::endl;

    Algorithms::QuickSort(arr,0, 7);

    <span style="color: blue">for</span>(size_t i = 0; i != 8; ++i)
    {
        std::cout&lt;&lt;arr[i]&lt;&lt;<span style="color: #a31515">" "</span>;
    }
    std::cout&lt;&lt;std::endl;

    std::vector&lt;<span style="color: blue">int</span>&gt; vec;
    vec.push_back(3);
    vec.push_back(1);
    vec.push_back(4);
    vec.push_back(1);
    vec.push_back(7);
    vec.push_back(6);

    <span style="color: blue">for</span>(std::vector&lt;<span style="color: blue">int</span>&gt;::iterator iter = vec.begin();
        iter != vec.end(); ++ iter)
    {
        std::cout&lt;&lt;*iter&lt;&lt;<span style="color: #a31515">" "</span>;
    }
    std::cout&lt;&lt;std::endl;

    std::sort(vec.begin(), vec.end());

    <span style="color: blue">for</span>(std::vector&lt;<span style="color: blue">int</span>&gt;::iterator iter = vec.begin();
        iter != vec.end(); ++ iter)
    {
        std::cout&lt;&lt;*iter&lt;&lt;<span style="color: #a31515">" "</span>;
    }
    std::cout&lt;&lt;std::endl;

    <span style="color: blue">return </span>0;
}

</pre><img src ="http://www.cppblog.com/mymsdn/aggbug/75693.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2009-03-06 03:03 <a href="http://www.cppblog.com/mymsdn/archive/2009/03/06/quicksort.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>