﻿<?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++博客-逆水行舟</title><link>http://www.cppblog.com/yearner/</link><description>智慧需要点滴的积累</description><language>zh-cn</language><lastBuildDate>Sat, 04 Apr 2026 17:16:13 GMT</lastBuildDate><pubDate>Sat, 04 Apr 2026 17:16:13 GMT</pubDate><ttl>60</ttl><item><title>关于MSVCRTD.lib的编译错误</title><link>http://www.cppblog.com/yearner/archive/2010/07/14/120309.html</link><dc:creator>(Leyn)顽主</dc:creator><author>(Leyn)顽主</author><pubDate>Wed, 14 Jul 2010 03:30:00 GMT</pubDate><guid>http://www.cppblog.com/yearner/archive/2010/07/14/120309.html</guid><wfw:comment>http://www.cppblog.com/yearner/comments/120309.html</wfw:comment><comments>http://www.cppblog.com/yearner/archive/2010/07/14/120309.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yearner/comments/commentRss/120309.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yearner/services/trackbacks/120309.html</trackback:ping><description><![CDATA[MFC的工程包smcinst，编译后出现以下错误<br>MSVCRTD.lib(MSVCRTD.dll) &nbsp; : &nbsp; error &nbsp; LNK2005: &nbsp; _free &nbsp; already &nbsp; defined &nbsp; in &nbsp; libcmtd.lib(dbgheap.obj) <br>MSVCRTD.lib(MSVCRTD.dll) &nbsp; : &nbsp; error &nbsp; LNK2005: &nbsp; _malloc &nbsp; already &nbsp; defined &nbsp; in &nbsp; libcmtd.lib(dbgheap.obj) <br>....<br>LINK &nbsp; : &nbsp; warning &nbsp; LNK4098: &nbsp; defaultlib &nbsp; "MSVCRTD " &nbsp; conflicts &nbsp; with &nbsp; use &nbsp; of &nbsp; other &nbsp; libs; &nbsp; use &nbsp; /NODEFAULTLIB:library <br>Debug/NKOTwain.ocx &nbsp; : &nbsp; fatal &nbsp; error &nbsp; LNK1169: &nbsp; one &nbsp; or &nbsp; more &nbsp; multiply &nbsp; defined &nbsp; symbols &nbsp; found <br>Error &nbsp; executing &nbsp; link.exe. <br><br><br>标准程序库有关的选项: /ML、/MLd、/MT、/MTd、/MD、/MDd。<br>这些选项对应编译器应用程序所要使用运行时C标准程序库。<br>/ML(缺省选项)对应单线程静态版的标准程序库(libc.lib)；<br>/MT对应多线程静态版标准库(libcmt.lib)，此时编译器会自动定义_MT宏；<br>/MD对应多线程DLL版(导入库msvcrt.lib，DLL是msvcrt.dll)，编译器自动定义_MT和_DLL两个宏。后面加d的选项都会让编译器自动多定义一个_DEBUG宏，表示要使用对应标准库的调试版，因此/MLd对应调试版单线程静态标准库(libcd.lib)，<br>/MTd对应调试版多线程静态标准库(libcmtd.lib)；<br>/MDd对应调试版多线程DLL标准库(导入库msvcrtd.lib，DLL是msvcrtd.dll)。<br><br>因此，上述的conflicts原因是出现了对运行库版本调用的不一致。<br>将有相互调用关系的工程属性-&gt;代码生成-&gt;运行时库 设置成统一选项，如 /mtd. 
<img src ="http://www.cppblog.com/yearner/aggbug/120309.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yearner/" target="_blank">(Leyn)顽主</a> 2010-07-14 11:30 <a href="http://www.cppblog.com/yearner/archive/2010/07/14/120309.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> Quoted printable 编码说明</title><link>http://www.cppblog.com/yearner/archive/2008/11/20/67421.html</link><dc:creator>(Leyn)顽主</dc:creator><author>(Leyn)顽主</author><pubDate>Thu, 20 Nov 2008 13:46:00 GMT</pubDate><guid>http://www.cppblog.com/yearner/archive/2008/11/20/67421.html</guid><wfw:comment>http://www.cppblog.com/yearner/comments/67421.html</wfw:comment><comments>http://www.cppblog.com/yearner/archive/2008/11/20/67421.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yearner/comments/commentRss/67421.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yearner/services/trackbacks/67421.html</trackback:ping><description><![CDATA[<font size="2" face="Default Sans Serif, Verdana, Arial, Helvetica, sans-serif">
<p class="EC_MsoNormal"><span lang="EN-US"><span></span></span></p>
<p class="EC_MsoListParagraph" style="text-indent: -1cm;"><span style="font-family: 'arial','sans-serif';" lang="EN-US"><span><font size="3">3.2</font><span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><font size="3"><span style="font-family: 'arial','sans-serif';" lang="EN-US">Quoted printable </span><span style="font-family: 仿宋_GB2312;">编码</span><span style="font-family: 'arial','sans-serif';" lang="EN-US"></span></font></p>
<p class="EC_MsoListParagraph" style="text-indent: 0cm;"><font size="3"><span lang="EN-US"><span><font face="Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span style="font-family: 'arial','sans-serif';" lang="EN-US">QP </span><span style="font-family: 仿宋_GB2312;">编码用于表示含有大量对应可打印字符的数组，这种编码方式使字符单元在传输过程中被更改的可能性很小。如果正在编码的数据大部分是</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">ASCII</span><span style="font-family: 仿宋_GB2312;">文本，那么编码后的形式具有很高的可读性。一个完全是</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">ASCII</span><span style="font-family: 仿宋_GB2312;">值的正文数据由</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">QP</span><span style="font-family: 仿宋_GB2312;">编码后可以保证数据在字符翻译或经由网关时数据的完整性。</span><span style="font-family: 'arial','sans-serif';" lang="EN-US"></span></font></p>
<p class="EC_MsoListParagraph" style="text-indent: 0cm;"><font size="3"><span style="font-family: 'arial','sans-serif';" lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 仿宋_GB2312;">编码规则如下：</span><span style="font-family: 'arial','sans-serif';" lang="EN-US"></span></font></p>
<p class="EC_MsoListParagraph" style="text-indent: 0cm;"><font size="3"><span style="font-family: 'arial','sans-serif';" lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 仿宋_GB2312;">规则</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">1</span><span style="font-family: 仿宋_GB2312;">：</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">(</span><span style="font-family: 仿宋_GB2312;">一般</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">8</span><span style="font-family: 仿宋_GB2312;">位组的表示方式</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">), </span><span style="font-family: 仿宋_GB2312;">任何的八位组，都可以用</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">&#8221;=&#8221;</span><span style="font-family: 仿宋_GB2312;">后加该八位组的</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">16</span><span style="font-family: 仿宋_GB2312;">进制值来表示，除了那些根据数据编码规范中新行的惯例来指定短行的表示单位。必须用大写字母。比如值是</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">12 </span><span style="font-family: 仿宋_GB2312;">，则表示为</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">&#8221;=0C&#8221;</span><span style="font-family: 仿宋_GB2312;">。</span><span style="font-family: 'arial','sans-serif';" lang="EN-US"></span></font></p>
<p class="EC_MsoListParagraph" style="text-indent: 0cm;"><font size="3"><span style="font-family: 'arial','sans-serif';" lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 仿宋_GB2312;">规则</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">2</span><span style="font-family: 仿宋_GB2312;">：</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">(</span><span style="font-family: 仿宋_GB2312;">文字表示</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">)</span><span style="font-family: 仿宋_GB2312;">值在</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">33-60 </span><span style="font-family: 仿宋_GB2312;">，以及</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">62-126</span><span style="font-family: 仿宋_GB2312;">的八位组</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">(</span><span style="font-family: 仿宋_GB2312;">包含头尾值</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">)</span><span style="font-family: 仿宋_GB2312;">，可以表示成那些八位组对应的</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">ASCII</span><span style="font-family: 仿宋_GB2312;">字符。</span><span style="font-family: 'arial','sans-serif';" lang="EN-US"></span></font></p>
<p class="EC_MsoListParagraph" style="text-indent: 0cm;"><font size="3"><span style="font-family: 'arial','sans-serif';" lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 仿宋_GB2312;">规则</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">3</span><span style="font-family: 仿宋_GB2312;">：</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">(</span><span style="font-family: 仿宋_GB2312;">空格</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">) </span><span style="font-family: 仿宋_GB2312;">值是</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">9</span><span style="font-family: 仿宋_GB2312;">和</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">32</span><span style="font-family: 仿宋_GB2312;">的八位组可以分别表示为</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">ASCII </span><span style="font-family: 仿宋_GB2312;">的</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">TAB</span><span style="font-family: 仿宋_GB2312;">和</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">SPACE</span><span style="font-family: 仿宋_GB2312;">值，但是不可以出现在编码行的末尾。任何在编码行的</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">TAB</span><span style="font-family: 仿宋_GB2312;">或</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">SPACE</span><span style="font-family: 仿宋_GB2312;">字符必须后面有可打印字符出现。特殊情况下，编码行的末尾出现的</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">&#8221;=&#8221;</span><span style="font-family: 仿宋_GB2312;">，表示断行，其前面可能是一个或多个</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">TAB</span><span style="font-family: 仿宋_GB2312;">或</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">SPACE</span><span style="font-family: 仿宋_GB2312;">。</span><span style="font-family: 'Arial','sans-serif';"> </span><span style="font-family: 仿宋_GB2312;">实行这条规则的原因是一些</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">METs(Message Transport Agents-</span><span style="font-family: 仿宋_GB2312;">消息传输单元</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">)</span><span style="font-family: 仿宋_GB2312;">会在文本末尾补上</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">SPACE</span><span style="font-family: 仿宋_GB2312;">，因此，解码时，任何跟在行后的空格必须删除。</span><span style="font-family: 'arial','sans-serif';" lang="EN-US"></span></font></p>
<p class="EC_MsoListParagraph" style="text-indent: 0cm;"><font size="3"><span style="font-family: 'arial','sans-serif';" lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 仿宋_GB2312;">规则</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">4</span><span style="font-family: 仿宋_GB2312;">：</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">(</span><span style="font-family: 仿宋_GB2312;">断行</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">)</span><span style="font-family: 仿宋_GB2312;">在原文中的断行必须表示成协议中的断行符</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">-CRLF</span><span style="font-family: 仿宋_GB2312;">序列<span style="color: red;">（</span></span><span style="color: red; font-family: 'arial','sans-serif';" lang="EN-US">"=0D=0A&#8221; </span><span style="color: red; font-family: 仿宋_GB2312;">）</span><span style="font-family: 仿宋_GB2312;">。由于非文本类型的规范表示一般不包括断行，所以这种类型的</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">qp</span><span style="font-family: 仿宋_GB2312;">编码没有硬换行。通常，</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">base64</span><span style="font-family: 仿宋_GB2312;">编码在二进制编码上更占优势。</span><span style="font-family: 'arial','sans-serif';" lang="EN-US"></span></font></p>
<p class="EC_MsoListParagraph" style="text-indent: 0cm;"><font size="3"><span style="font-family: 'arial','sans-serif';" lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 仿宋_GB2312;">规则</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">5</span><span style="font-family: 仿宋_GB2312;">：</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">(</span><span style="font-family: 仿宋_GB2312;">软换行</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">)QP</span><span style="font-family: 仿宋_GB2312;">编码要求编码后每行不能超过</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">76</span><span style="font-family: 仿宋_GB2312;">个字符。当超过这个限制时，将适用软换行，用</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">&#8221;=&#8221;</span><span style="font-family: 仿宋_GB2312;">表示编码行的断行，后接</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">CRLF</span><span style="font-family: 仿宋_GB2312;">。（</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">76</span><span style="font-family: 仿宋_GB2312;">的限制包括</span><span style="font-family: 'arial','sans-serif';" lang="EN-US">&#8221;=&#8221;</span><span style="font-family: 仿宋_GB2312;">）。</span><span style="font-family: 'arial','sans-serif';" lang="EN-US"></span></font></p>
<p class="EC_MsoListParagraph" style="text-indent: 0cm;"><span style="font-family: 'arial','sans-serif';" lang="EN-US"><font size="3"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font></span></p>
</font><img src ="http://www.cppblog.com/yearner/aggbug/67421.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yearner/" target="_blank">(Leyn)顽主</a> 2008-11-20 21:46 <a href="http://www.cppblog.com/yearner/archive/2008/11/20/67421.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Base 64 编码说明</title><link>http://www.cppblog.com/yearner/archive/2008/11/20/67418.html</link><dc:creator>(Leyn)顽主</dc:creator><author>(Leyn)顽主</author><pubDate>Thu, 20 Nov 2008 13:45:00 GMT</pubDate><guid>http://www.cppblog.com/yearner/archive/2008/11/20/67418.html</guid><wfw:comment>http://www.cppblog.com/yearner/comments/67418.html</wfw:comment><comments>http://www.cppblog.com/yearner/archive/2008/11/20/67418.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yearner/comments/commentRss/67418.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yearner/services/trackbacks/67418.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 3.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Base 64编码Base 64 编码采用了US-ASCII 的65个字符集，每个字符都由6位来表示（0-&nbsp; 2 6-1），而第65位字符&#8220;=&#8221;用来表示字符串的结束。&nbsp;                        ...&nbsp;&nbsp;<a href='http://www.cppblog.com/yearner/archive/2008/11/20/67418.html'>阅读全文</a><img src ="http://www.cppblog.com/yearner/aggbug/67418.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yearner/" target="_blank">(Leyn)顽主</a> 2008-11-20 21:45 <a href="http://www.cppblog.com/yearner/archive/2008/11/20/67418.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MIME邮件格式说明</title><link>http://www.cppblog.com/yearner/archive/2008/11/20/67417.html</link><dc:creator>(Leyn)顽主</dc:creator><author>(Leyn)顽主</author><pubDate>Thu, 20 Nov 2008 13:44:00 GMT</pubDate><guid>http://www.cppblog.com/yearner/archive/2008/11/20/67417.html</guid><wfw:comment>http://www.cppblog.com/yearner/comments/67417.html</wfw:comment><comments>http://www.cppblog.com/yearner/archive/2008/11/20/67417.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yearner/comments/commentRss/67417.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yearner/services/trackbacks/67417.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 邮件格式说明Mutiple Internet Mail ExtensionsRefer to Internet Official Protocol Standards RFC 8221&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 概述网络间传递的电子邮件需要公共认同的格式，以便于客户端邮箱软件识别拆解其间的信息。邮件本身是由ASCII字符构成...&nbsp;&nbsp;<a href='http://www.cppblog.com/yearner/archive/2008/11/20/67417.html'>阅读全文</a><img src ="http://www.cppblog.com/yearner/aggbug/67417.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yearner/" target="_blank">(Leyn)顽主</a> 2008-11-20 21:44 <a href="http://www.cppblog.com/yearner/archive/2008/11/20/67417.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转 ]浅谈C++的智能指针 </title><link>http://www.cppblog.com/yearner/archive/2008/11/09/66447.html</link><dc:creator>(Leyn)顽主</dc:creator><author>(Leyn)顽主</author><pubDate>Sun, 09 Nov 2008 12:43:00 GMT</pubDate><guid>http://www.cppblog.com/yearner/archive/2008/11/09/66447.html</guid><wfw:comment>http://www.cppblog.com/yearner/comments/66447.html</wfw:comment><comments>http://www.cppblog.com/yearner/archive/2008/11/09/66447.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yearner/comments/commentRss/66447.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yearner/services/trackbacks/66447.html</trackback:ping><description><![CDATA[<h1 id="subject_tpc" class="fl">浅谈C++的智能指针</h1>
<div class="tpc_content" id="read_tpc">内存泄露是C++程序员都头疼的大<span onclick="sendmsg('pw_ajax.php','action=relatetag&amp;tagname=问题',this.id)" style="border-bottom: 1px solid #fa891b; cursor: pointer;" id="rlt_4">问题</span>。C++缺乏像JAVA、C#一样，拥有GC这么一项有利的武器，它将内存管理的部分<span onclick="sendmsg('pw_ajax.php','action=relatetag&amp;tagname=权限',this.id)" style="border-bottom: 1px solid #fa891b; cursor: pointer;" id="rlt_2">权限</span>交给了程序员。虽然GC的存在节约了开发、排错的时间与成本，但是C++为了追求运行<span onclick="sendmsg('pw_ajax.php','action=relatetag&amp;tagname=速度',this.id)" style="border-bottom: 1px solid #fa891b; cursor: pointer;" id="rlt_1">速度</span>而20年来坚决不予补充进其标准。（题外话：C++通过加大开发难度去换取执行速度的做法，在现在看来不知是否能给与正面的评价，还是留给将来再说吧。）<br><br>&nbsp; 从此，在堆上申请了内存忘了释放、所造成的内存泄露的问题就一直困扰着C++程序员。也许为了稍许弥补没有垃圾回收器所造成的开发门槛高，各大厂商开发的C++库中都像COM学习引入智能指针试图解决部分目前存在的问题。<br><br>&nbsp;
智能指针是存储指向动态分配（堆）对象指针的类, 用于生存期控制,
能够确保自动正确的销毁动态分配的对象，防止内存泄露。它的一种通用实现技术是使用引用计数(reference
count)。智能指针类将一个计数器与类指向的对象相关联，引用计数跟踪该类有多少个对象共享同一指针。每次创建类的新对象时，初始化指针并将引用计数
置为1；当对象作为另一对象的副本而创建时，拷贝构造函数拷贝指针并增加与之相应的引用计数；对一个对象进行赋值时，赋值操作符减少左操作数所指对象的引
用计数（如果引用计数为减至0，则删除对象），并增加右操作数所指对象的引用计数；调用析构函数时，构造函数减少引用计数（如果引用计数减至0，则删除基
础对象）。<br><br>&nbsp; 说到智能指针，我们一定要看看标准C++库提供的&#8220;搞笑的&#8221;智能指针:auto_ptr。<br><br>&nbsp;
标准库中提供了C++程序的基本设施。虽然C++标准库随着C++标准折腾了许多年，直到标准的出台才正式定型，网上评论C++标准库时都说：&#8220;在标准库
的实现上却很令人欣慰得看到多种实现，并且已被实践证明为有工业级别强度的佳作。&#8221;但目前的标准C++中，只有一种独苗智能指
针：std::auto_ptr。<br><br>&nbsp; auto_ptr指针是一个RAII对象,它初始化时获得资源,析构时自动释放资源(生命期结束).它的缺点数不胜数：<br> 1、auto_ptr要求一个对象只能有一个拥有者，严禁一物二主<br> 2、缺少对引用数和数组的支持。<br> 3、不可将auto_ptr对象作为STL容器的元素。C++标准明确禁止这样做，否则可能会碰到不可预见的结果。（这一条晕死一<span onclick="sendmsg('pw_ajax.php','action=relatetag&amp;tagname=大片',this.id)" style="border-bottom: 1px solid #fa891b; cursor: pointer;" id="rlt_5">大片</span>）。<br>4、auto_ptr在被复制的时候会传输所有权<br><br> 反正由此可见：标准库的智能指针就是无甚大用。<br><br>&nbsp; &nbsp; 在这样的情况下，C++标准委员会自然需要考虑引入新的智能指针。目前由C++标准委员会库工作组发起的Boost 组织开发了Boost系列智能指针。<br><br>&nbsp; 在Boost中的智能指针有五种： scoped_ptr，scoped_array，shared_ptr，shared_array，weak_ptr.<br><br>前4种完全是针对标准库中的auto_ptr提出解决方案，如：scope_ptr是针对&#8220;auto_ptr在被复制的时候会传输所有权&#8221;这一弱点提出的。最后一种没见过，看名字像是弱引用智能指针，我怀疑<span onclick="sendmsg('pw_ajax.php','action=relatetag&amp;tagname=是不是',this.id)" style="border-bottom: 1px solid #fa891b; cursor: pointer;" id="rlt_3">是不是</span>类似于JAVA中弱引用一样,有待进一步学习。</div><img src ="http://www.cppblog.com/yearner/aggbug/66447.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yearner/" target="_blank">(Leyn)顽主</a> 2008-11-09 20:43 <a href="http://www.cppblog.com/yearner/archive/2008/11/09/66447.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]C++中的指针--智能指针</title><link>http://www.cppblog.com/yearner/archive/2008/11/09/66445.html</link><dc:creator>(Leyn)顽主</dc:creator><author>(Leyn)顽主</author><pubDate>Sun, 09 Nov 2008 12:37:00 GMT</pubDate><guid>http://www.cppblog.com/yearner/archive/2008/11/09/66445.html</guid><wfw:comment>http://www.cppblog.com/yearner/comments/66445.html</wfw:comment><comments>http://www.cppblog.com/yearner/archive/2008/11/09/66445.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yearner/comments/commentRss/66445.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yearner/services/trackbacks/66445.html</trackback:ping><description><![CDATA[<p>Smart Pointer是<a  href="http://www.bc-cn.net/Article/kfyy/cjj/Index.html" class="channel_keylink">C++</a>中的一个大题目，要说清楚他的所有好处很需要费点力气。我就一个功能一个功能的说。有我理解不透的地方希望大家指点。<br><br>1.copy-to-write<br>当生成一个<a  href="http://www.bc-cn.net/Article/kfyy/cjj/Index.html" class="channel_keylink">C++</a> object的时候如果这个class很大，这个object会占用很多空间。那么每生成一个就占用一片空间，这样会占用很多系统资源。同时降低效率。一个解决方法就是对用拷贝构造<a  href="http://www.bc-cn.net/Article/Search.asp?Field=Title&amp;ClassID=&amp;keyword=%BA%AF%CA%FD" class="channel_keylink">函数</a>生成的object，让他不存储数据，而只存储一个指向原来object数据的<a  href="http://www.bc-cn.net/Article/Search.asp?Field=Title&amp;ClassID=&amp;keyword=%D6%B8%D5%EB&amp;Submit=+%CB%D1%CB%F7+" class="channel_keylink">指针</a>。 这样空间就节省了很多。但问题在于这样两个object完全联结在了一起。如果修改了其中一个，另一个也跟着变了。所以这种方法不可取。这里讲的 copy-to-write技术就是解决这类问题的方法。当通过引用一个已有object去拷贝构造新object时，新object只有一个指向已有 object的<a  href="http://www.bc-cn.net/Article/Search.asp?Field=Title&amp;ClassID=&amp;keyword=%D6%B8%D5%EB&amp;Submit=+%CB%D1%CB%F7+" class="channel_keylink">指针</a>。
这两个object共享数据。直到其中一个需要修改数据的时候，再把这两块数据分离。这里举一个最简化的例子。假设一个class叫
CLargeObject，里面存有很多数据。我们用一个inner
class来把所有数据放在一起，叫CData。CData里面存有大量数据，例如一个<a  href="http://www.bc-cn.net/Article/sjk/Index.html" class="channel_keylink">数据库</a>。这里用最简单的模型来表示，假设只有一个整数int m_nVal; CData里面需要包含另一个变量。叫作索引数目(reference count)。它记录了指向这个CData object的来自CLargetObject类的<a  href="http://www.bc-cn.net/Article/Search.asp?Field=Title&amp;ClassID=&amp;keyword=%D6%B8%D5%EB&amp;Submit=+%CB%D1%CB%F7+" class="channel_keylink">指针</a>各数。也就是说，总共有多少CLargeObject的object正在引用着当前的CData object。<br><br>class CLargeObject<br>{<br>private:<br>&nbsp;&nbsp;&nbsp;&nbsp;struct CData<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;private:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int m_nVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int m_nReferenceCount;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>};<br><br>对于每个CLargeObject的object，我们用一个CData类的<a  href="http://www.bc-cn.net/Article/Search.asp?Field=Title&amp;ClassID=&amp;keyword=%D6%B8%D5%EB&amp;Submit=+%CB%D1%CB%F7+" class="channel_keylink">指针</a>来指向其数据。<br>CData *m_pData;<br><br>CLargeObject至少有两个构造<a  href="http://www.bc-cn.net/Article/Search.asp?Field=Title&amp;ClassID=&amp;keyword=%BA%AF%CA%FD" class="channel_keylink">函数</a>。第一个是标准的构造<a  href="http://www.bc-cn.net/Article/Search.asp?Field=Title&amp;ClassID=&amp;keyword=%BA%AF%CA%FD" class="channel_keylink">函数</a>，初始化其数据。这时数据是唯一的，所以必须新生成一个CData的object来存储数据。<br>CLargeObject::CLargeObject(int nVal)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;m_pData = new Data(nVal);<br>}<br>而对于CData类的构造<a  href="http://www.bc-cn.net/Article/Search.asp?Field=Title&amp;ClassID=&amp;keyword=%BA%AF%CA%FD" class="channel_keylink">函数</a>而言，初始化他的CLargeObject是第一个指向他的，这一时刻索引数目m_nReferenceCount是1。<br>CLargeObject::Data::Data(int nVal) : m_nVal(nVal), m_nReferenceCount(1) {}<br><br>CLargeObject的第二个构造<a  href="http://www.bc-cn.net/Article/Search.asp?Field=Title&amp;ClassID=&amp;keyword=%BA%AF%CA%FD" class="channel_keylink">函数</a>是拷贝构造(copy constructor)。这样生成的object不需要有新的数据，和已有的object共享数据就可以了。这是索引数目需要加1。表示又有一个object指向当前的CData了。<br>CLargeObject::CLargeObject(const CLargeObject &amp;ob) // copy constructor<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;ob.m_pData-&gt;m_nReferenceCount++;<br>&nbsp;&nbsp;&nbsp;&nbsp;m_pData = ob.m_pData;<br>}<br><br><br>这样CLargeObject就构造好了，使用了可能的最少的内存。下面看看他的析够<a  href="http://www.bc-cn.net/Article/Search.asp?Field=Title&amp;ClassID=&amp;keyword=%BA%AF%CA%FD" class="channel_keylink">函数</a>(destructor)。当一个object被delete的时候，它的数据不一定无效，如果别的object还在引用着这个数据，数据需要留下来。当然，数据的索引数目无论如何都要减1。<br>CLargeObject::~CLargeObject()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;if (--m_pData-&gt;m_nReferenceCount == 0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete m_pData;<br>}<br><br>下面看一看赋值操作。先说用已有的CLargeObject赋值给这个CLargeObject。这时当前CLargeObject里面的数据要指向已有的这个object，就搞定了。<br>CLargeObject&amp; CLargeObject::operator = (const CLargeObject&amp; ob)&nbsp;&nbsp;&nbsp;&nbsp;// copy assignment<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;ob.m_pData-&gt;m_nReferenceCount++;<br>&nbsp;&nbsp;&nbsp;&nbsp;if (--m_pData-&gt;m_nReferenceCount == 0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete m_pData;<br>&nbsp;&nbsp;&nbsp;&nbsp;m_pData = ob.m_pData;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;return *this;<br>}<br><br>再来看看如何对CLargeObject里面的数据进行真正的修改。这样就一定需要对当前的object独立操作了，否则就影响到了其它指向同一块数据的CLargeObject。这样CData类需要一个新的<a  href="http://www.bc-cn.net/Article/Search.asp?Field=Title&amp;ClassID=&amp;keyword=%BA%AF%CA%FD" class="channel_keylink">函数</a>，生成只用于当前CLargetObject的数据。如果当前的引用数目是1，那么当然这个CData就是只用于这个CLargeObject的了。否则就重新new一个CData返回。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Data* CLargeObject::CData::get_own_copy()&nbsp;&nbsp;&nbsp;&nbsp;// clone if necessary<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (m_nReferenceCount==1)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return this;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_nReferenceCount--;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new Data(m_nVal);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>CLargeObject修改前用这个<a  href="http://www.bc-cn.net/Article/Search.asp?Field=Title&amp;ClassID=&amp;keyword=%BA%AF%CA%FD" class="channel_keylink">函数</a>得到唯一的object，然后对它赋值。<br>void CLargeObject::SetVal(int nNewVal)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;m_pData = m_pData-&gt;get_own_copy();<br>&nbsp;&nbsp;&nbsp;&nbsp;m_pData-&gt;m_nVal = nNewVal;<br>}<br>对于所有可能改变CData值的操作，都需要用这种方法。<br><br>下面是只读<a  href="http://www.bc-cn.net/Article/Search.asp?Field=Title&amp;ClassID=&amp;keyword=%BA%AF%CA%FD" class="channel_keylink">函数</a>，简单。直接返回值，什么特殊的都不用作。<br>int CLargeObject::GetVal() const<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;return m_pData-&gt;m_nVal;<br>}<br><br><br>这样copy-to-write技术就实现了。下面把完整的程序写一下：<br>class CLargeObject<br>{<br>public:<br>&nbsp;&nbsp;&nbsp;&nbsp;CLargeObject(int nVal);<br>&nbsp;&nbsp;&nbsp;&nbsp;CLargeObject(const CLargeObject &amp;ob);<br>&nbsp;&nbsp;&nbsp;&nbsp;~CLargeObject();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;CLargeObject&amp; operator = (const CLargeObject&amp; ob);<br>&nbsp;&nbsp;&nbsp;&nbsp;void SetVal(int nNewVal);<br>&nbsp;&nbsp;&nbsp;&nbsp;int GetVal() const;<br>private:<br>&nbsp;&nbsp;&nbsp;&nbsp;struct Data<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;public:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Data(int nVal) : m_nVal(nVal), m_nReferenceCount(1) {}<br>&nbsp;&nbsp;&nbsp;&nbsp;private: <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;friend class CLargeObject;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Data* get_own_copy()&nbsp;&nbsp;&nbsp;&nbsp;// clone if necessary<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (m_nReferenceCount==1)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return this;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_nReferenceCount--;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new Data(m_nVal);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// control variables.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int m_nReferenceCount;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// actual data portion<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int m_nVal;<br>&nbsp;&nbsp;&nbsp;&nbsp;};</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;Data *m_pData;<br>};</p>
<p>CLargeObject::CLargeObject(int nVal)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;m_pData = new Data(nVal);<br>}</p>
<p>CLargeObject::CLargeObject(const CLargeObject &amp;ob) // copy constructor<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;ob.m_pData-&gt;m_nReferenceCount++;<br>&nbsp;&nbsp;&nbsp;&nbsp;m_pData = ob.m_pData;<br>}</p>
<p>CLargeObject::~CLargeObject()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;if (--m_pData-&gt;m_nReferenceCount == 0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete m_pData;<br>}</p>
<p>CLargeObject&amp; CLargeObject::operator = (const CLargeObject&amp; ob)&nbsp;&nbsp;&nbsp;&nbsp;// copy assignment<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;ob.m_pData-&gt;m_nReferenceCount++;<br>&nbsp;&nbsp;&nbsp;&nbsp;if (--m_pData-&gt;m_nReferenceCount == 0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete m_pData;<br>&nbsp;&nbsp;&nbsp;&nbsp;m_pData = ob.m_pData;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;return *this;<br>}</p>
<p>void CLargeObject::SetVal(int nNewVal)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;m_pData = m_pData-&gt;get_own_copy();<br>&nbsp;&nbsp;&nbsp;&nbsp;m_pData-&gt;m_nVal = nNewVal;<br>}</p>
<p>int CLargeObject::GetVal() const<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;return m_pData-&gt;m_nVal;<br>}<br><br><br>很多存储数据的系统class，如string，CString等都有这种设计。所以记住这个应用是很有必要的。</p><img src ="http://www.cppblog.com/yearner/aggbug/66445.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yearner/" target="_blank">(Leyn)顽主</a> 2008-11-09 20:37 <a href="http://www.cppblog.com/yearner/archive/2008/11/09/66445.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]利用Rational Rose进行C++代码和数据库结构分析</title><link>http://www.cppblog.com/yearner/archive/2008/10/28/65350.html</link><dc:creator>(Leyn)顽主</dc:creator><author>(Leyn)顽主</author><pubDate>Tue, 28 Oct 2008 09:36:00 GMT</pubDate><guid>http://www.cppblog.com/yearner/archive/2008/10/28/65350.html</guid><wfw:comment>http://www.cppblog.com/yearner/comments/65350.html</wfw:comment><comments>http://www.cppblog.com/yearner/archive/2008/10/28/65350.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/yearner/comments/commentRss/65350.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yearner/services/trackbacks/65350.html</trackback:ping><description><![CDATA[<table cellSpacing=0 cellPadding=0 width=760 align=center border=0>
    <tbody>
        <tr>
            <td class=title vAlign=center align=middle height=56><strong><font color=#ff0000 size=3>利用Rational Rose进行C++代码和数据库结构分析<br><!-- #EndEditable --></font></strong></td>
        </tr>
        <tr>
            <td class=formtitle align=middle height=40><!-- #BeginEditable "2" -->申 震杰, IBM 中国软件开发中心软件工程师<br><!-- #EndEditable --></td>
        </tr>
    </tbody>
</table>
<table height=65 cellSpacing=0 cellPadding=0 width=760 align=center border=0>
    <tbody>
        <tr>
            <td class=content height=65><!-- #BeginEditable "3" -->
            <table class=p11 cellSpacing=0 cellPadding=0 width="100%" align=center border=0>
                <tbody>
                    <tr>
                        <td class=content style="WORD-WRAP: break-word" height=52>
                        <p>本文内容包括: <br>　<a href="http://www.uml.org.cn/umltools/200607123.htm#1"><u><font color=#800080>一．Rational Rose逆向工程介绍 </font></u></a><br>　<a href="http://www.uml.org.cn/umltools/200607123.htm#2"><u><font color=#800080>二．如何用Rational Rose进行C++代码分析 </font></u></a><br>　<a href="http://www.uml.org.cn/umltools/200607123.htm#3"><u><font color=#800080>三．如何用Rational Rose进行数据库结构分析</font></u></a> <br>　<a href="http://www.uml.org.cn/umltools/200607123.htm#4"><u><font color=#800080>四．如何得到逆向工程的模型图 </font></u></a><br>　<a href="http://www.uml.org.cn/umltools/200607123.htm#5"><u><font color=#800080>五．总结</font></u></a> <br>　<a href="http://www.uml.org.cn/umltools/200607123.htm#6"><u><font color=#800080>注释</font></u></a> <br><br>　Rational Rose是利用UML（统一建模语言）进行分析和设计面向对象软件系统的强大的可视化工具，可以进行项目需求分析、结构规划和生成框架代码，还可以支持从现有系统逆向转出工程代码，生成Rose模型的功能。<br>2004年10月，IBM推出了支持最新的UML2.0的可视化建模工具 Rational Software Architect（见注释①） 和IBM Rational Software Modeler（见注释②）。虽然它们支持在建模功能上有了更好的改进、支持了更新的标准，但是RSA的精彩功能主要是集中在对Java应用的支持，而IBM Rational Software Modeler则是主要关注系统的模型设计，如果要从结构上分析C++编写的系统的代码，Rational Rose还是首选的工具。</p>
                        <p>接下来的文章将会对如何利用Rational Rose 的逆向转出工程来进行系统分析进行更加详细地阐述。</p>
                        <p><strong><a name=1></a>一．Rational Rose逆向工程介绍</strong></p>
                        <p>逆向工程（Reverse Engineer）就是从现有系统的代码来生成模型的功能。分析已有的代码其主要的目的就是了解代码结构和数据结构，这些对应到模型图就是类图、数据模型图和组件图（对UML各种模型图的描述见注释③），也就是通过Rational Rose的逆向工程所得到的结果。Rational Rose所支持的逆向工程功能很强大，包括的编程语言有C++, VB, VC, Java, CORBA，以及数据库DDL脚本等等，并且可以直接连接DB2, SQLServer, Oracle和Sybase等数据库导入Schema并生成数据模型。</p>
                        <p>很多大型的C++开发的产品都涉及到数据库的使用，对这种大型系统的开发，尤其是做二次开发的情况下，主要的难点就是对源码和数据库结构的分析。而利用Rose的逆向工程这一功能，就可以完成代码'类图以及数据库Schema-&gt;数据模型图的转换，解决这两大难点，可以使开发和设计人员在对这种大型系统的升级、分析和开发中，更为方便、快捷、有条理地掌握系统结构，不用再为分析庞大的系统结构而头疼。</p>
                        <p><a name=2></a><strong>二．如何用Rational Rose进行C++代码分析</strong></p>
                        <p>这一节主要介绍用户如何使用Rose的逆向工程生成UML模型，并用来进行C++代码的结构分析。</p>
                        <p>Rational Rose可以支持标准C++和Visual C++的模型到代码的转换以及逆向工程。下面将详细地说明这两种C++ project的逆向工程的步骤和具体操作。</p>
                        <p>1． ANSI C++（标准C++）逆向工程（Reverse Engineer）使用标准C++逆向工程，需要在组件图（component view）中创建一个组件（component），设置好需要进行转换的组件的信息，也就是该组件的语言、所包含的文件、文件所在的路径、文件后缀等等信息，然后Reverse Engineer就可以根据给定的信息将代码转换成类图了。</p>
                        <p>a) 右键点击组件视图（Component View），选择New-&gt;Component，创建一个新的组件<br>　<img height=398 src="http://www.uml.org.cn/umltools/images/001.png" width=508> <br><br>　b) 将component的language属性设定为ANSI C++</p>
                        <p>①选中创建的component，点击右键，选中Open Specification<br>　<img height=283 src="http://www.uml.org.cn/umltools/images/003.png" width=405> </p>
                        <p>②在这个对话框中将该component的language设定为ANSI C++</p>
                        <p><img height=340 src="http://www.uml.org.cn/umltools/images/005.png" width=516><br></p>
                        <p>c) 配置该ANSI C++ component，设置好该component中包含的C++代码文件，并进行C++语言的详细设置</p>
                        <p>①选中该component，点击右键，选择ANSI C++-&gt;Open ANSI C++ Specification</p>
                        <p><img height=356 src="http://www.uml.org.cn/umltools/images/007.png" width=564><br></p>
                        <p>②把Source file root directory设定为你的C++源码文件所在的路径，并且将需要转换的文件添加到Project Files中，视你的需要来做其它的设定，比如：头文件扩展名等等。</p>
                        <p><img height=436 src="http://www.uml.org.cn/umltools/images/009.png" width=572></p>
                        <p>d) 将设置好的component转换成模型图</p>
                        <p>①选中设置好的component，点击右键，选中ANSI C++-&gt;Reverse Engineer</p>
                        <p><img height=330 src="http://www.uml.org.cn/umltools/images/011.png" width=572><br><br>　②选中需要转换的class，点击ok，一个component的逆向转换就完成了。</p>
                        <p><img height=431 src="http://www.uml.org.cn/umltools/images/013.png" width=547><br><br>　2． Visual C++ 在使用这个功能的时候，要求用户的机器上同时安装Visual Studio。Visual C++的逆向工程也需要首先创建一个component，并将该component的language属性设置为VC++。Rational Rose对VC++模型的转换是通过读取VC++ Project File的信息来实现的，用户只需要将对应的project file信息指定给component就可以了。</p>
                        <p>a) 将VC++ Project的信息赋给刚刚创建好的component。</p>
                        <p>①选择该component，点击右键，选择Assign To Project</p>
                        <p><img height=301 src="http://www.uml.org.cn/umltools/images/015.png" width=424><br></p>
                        <p>②在对话框中找到刚刚创建的component，右键点击并选择Properties。</p>
                        <p><img height=413 src="http://www.uml.org.cn/umltools/images/017.png" width=513><br></p>
                        <p>③在下面对话框中选中需要进行转换的Project，点击ok，该component就与需要转换的project关联上了。</p>
                        <p><img height=468 src="http://www.uml.org.cn/umltools/images/019.png" width=403><br><br>　b) 将设置好的component转换成模型图</p>
                        <p>选中设置好的component，点击右键，Update Model&#8230;，将会弹出确认对话框，选中需要转换的class，点击finish就可以了。</p>
                        <p><img height=262 src="http://www.uml.org.cn/umltools/images/021.png" width=376><br></p>
                        <p><img height=428 src="http://www.uml.org.cn/umltools/images/023.png" width=572> </p>
                        <p><a name=3></a><strong>三．如何用Rational Rose进行数据库结构分析</strong></p>
                        <p>利用Rational Rose可以进行关系数据库的数据模型设计并导出DDL语言脚本，相反还可以导入已有的DDL脚本生成数据模型以及连接SQLServer, DB2, Oracle等数据库并导入数据库的schema生成数据模型。</p>
                        <p>下面以SQL Server为例说明一下逆向转换工程的步骤。</p>
                        <p>a) 首先，选择Tools-&gt;Data Modeler-&gt; Reverse Engineer</p>
                        <p><img height=420 src="http://www.uml.org.cn/umltools/images/025.png" width=557><br>　<br>　b) 在进行逆向工程转换的过程中可以选择是从数据库还是DDL脚本进行转换，如果是DDL脚本转换，就直接给定DDL脚本文件位置就可以了。本例子给出的是连接SQLServer数据库将schema导入生成数据模型的过程，所以选中Database，进入下一步。</p>
                        <p><img height=345 src="http://www.uml.org.cn/umltools/images/027.png" width=572><br><br>　c) 填写数据库相关信息</p>
                        <p><img height=373 src="http://www.uml.org.cn/umltools/images/029.png" width=572><br><br>　d) 选中所有需要转换的schema</p>
                        <p><img height=373 src="http://www.uml.org.cn/umltools/images/031.png" width=572><br><br>　e) 选择需要将哪些数据库中的元素导入到数据模型中<br><img height=372 src="http://www.uml.org.cn/umltools/images/033.png" width=572> </p>
                        <p>转换操作会自动在组件图（Component View）中添加数据库组件，并在逻辑图（Logical View）中生成以《Schema》作为命名开头的数据模型。</p>
                        <p><img height=406 src="http://www.uml.org.cn/umltools/images/035.png" width=361><br><br>　打开数据模型，可以看到从数据库中转换过来的各个表和视图。</p>
                        <p><img height=540 src="http://www.uml.org.cn/umltools/images/037.png" width=572><br><br>　从数据模型图中可以看到表的结构以及各个表和视图之间的逻辑关系。</p>
                        <p><a name=4></a><strong>四．如何得到逆向工程的模型图</strong></p>
                        <p>在Rational Rose中，有些模型图是不会自动生成的，很多时候这个工作需要用户手工来完成。也就是说，Rational Rose只负责生成模型，包括模型中的元素、元素的属性以及各个元素之间的关系，但是需要用户做一些额外的工作来得到视图。</p>
                        <p>首先，通过逆向工程，用户已经得到了UML模型或者数据模型的各个组件以及它们之间的关系。 下一步需要在该模型上创建一个视图，它们可以是类图（class diagram，描述系统的静态结构）或者数据模型图（Data model digram，描述关系数据结构）。然后，手动从左边的explorer中将各个元素拖进视图中，在这个过程中，各个元素之间的关联关系会自动在图中表示出来，而不需要用户再做其他工作。</p>
                        <p>例如：生成一个数据模型的数据模型图的过程</p>
                        <p>从左边将数据模型中的数据元素拖到右边的数据模型图中，表CustomerCustomerDemo和表CustomerDemographics之间的依赖关系的菱形箭头是自动生成的，无需手工操作。</p>
                        <p><img height=380 src="http://www.uml.org.cn/umltools/images/039.png" width=572><br></p>
                        <p>一般来说，一个系统中所涉及的数据元素非常多，导致视图很拥挤，排版也非常困难。Rational Rose提供的自动排版功能可以很方便地帮助用户解决这个问题。</p>
                        <p>选择Format-&gt;Layout Diagram，系统会将图中的所有元素用最优方式重新排列，给用户一个清晰的视图。</p>
                        <p><img height=526 src="http://www.uml.org.cn/umltools/images/041.png" width=399><br></p>
                        <p><img height=519 src="http://www.uml.org.cn/umltools/images/043.png" width=772> </p>
                        <p><br>　<a name=5></a><strong>五．总结</strong></p>
                        <p>了解了Rational Rose的逆向工程功能，用户就可以方便地利用这一工具进行大型数据库相关的C++系统的分析和研究了。</p>
                        <p><a name=6></a><strong>注释</strong></p>
                        <p>①IBM Rational Software Architect是一个集成式设计和开发工具，使用户可以用UML模型驱动的开发方式开发出结构清晰的应用程序和服务。</p>
                        <p>②IBM Rational Software Modeler是基于UML2.0的可定制的可视化建模和设计工具，遵循它所提供的工作流程，可以使得系统设计师，系统分析师，设计人员等写出更为清晰的文档，更为有效地进行沟通和设计工作。</p>
                        <p>③UML提供的各种类型的模型描述图</p>
                        <p>用例图(Use Case Diagram)：描述系统提供的一个功能单元，主要目的是帮助开发团队以一种可视化的方式理解系统的功能需求，包括基于基本流程的"角色"（actors，也就是与系统交互的其他实体）关系，以及系统内用例之间的关系。</p>
                        <p>序列图(Sequence Diagram)：显示具体用例（或者是用例的一部分）的详细流程。</p>
                        <p>状态图(Statechart Diagram)：表示某个类所处的不同状态和该类的状态转换信息。</p>
                        <p>活动图(Activity Diagram)：表示在处理某个活动时，两个或者更多类对象之间的过程控制流。</p>
                        <p>类图(Class Diagram)：表示不同的实体（人、事物和数据）如何彼此相关；换句话说，它显示了系统的静态结构。</p>
                        <p>组件图(Component Diagram)：提供系统的物理视图。组件（Component）表示模型代码库、执行库和其它组件的信息。组件是代码的实际模块，组件图主要用户是负责控制代码和编译部署应用程序的人。有些组件是代码库，有些组件是运行组件，如执行文件或动态链接库（DLL）文件。）</p>
                        <p>部署图(Deployment View)：表示该软件系统如何部署到硬件环境中。</p>
                        <p>数据模型图(Data Model Diagram)：描述关系数据结构。</p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/yearner/aggbug/65350.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yearner/" target="_blank">(Leyn)顽主</a> 2008-10-28 17:36 <a href="http://www.cppblog.com/yearner/archive/2008/10/28/65350.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>COM 学习笔记(2)-引用计数</title><link>http://www.cppblog.com/yearner/archive/2008/10/08/63500.html</link><dc:creator>(Leyn)顽主</dc:creator><author>(Leyn)顽主</author><pubDate>Wed, 08 Oct 2008 13:57:00 GMT</pubDate><guid>http://www.cppblog.com/yearner/archive/2008/10/08/63500.html</guid><wfw:comment>http://www.cppblog.com/yearner/comments/63500.html</wfw:comment><comments>http://www.cppblog.com/yearner/archive/2008/10/08/63500.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yearner/comments/commentRss/63500.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yearner/services/trackbacks/63500.html</trackback:ping><description><![CDATA[引用计数<br>&nbsp;COM接口采用引用计数来控制组件的生命周期。<br>&nbsp;主要用AddRef ,Release 来进行内存管理，当客户从组件中取得一个接口时，此引用计数值将增1。当客户使用完某个接口后，组件的引用计数值将减1。<br>&nbsp;当引用计数值为0时，组件即可将自己从内从中删除。<br>&nbsp;<br>&nbsp;(1)正确使用引用计数的三条简单原则: <br>&nbsp;&nbsp;&nbsp;1)在返回之前调用AddRef.<br>&nbsp;&nbsp;&nbsp;2)使用完接口后调用Release.<br>&nbsp;&nbsp;&nbsp;3)在赋值之后调用AddRef(指针复制).<br>&nbsp;&nbsp;基本原则是避免在使用组件时，组件已被删除。<br>&nbsp;&nbsp;QueryInterface 和CreateInstance中已经调用了AddRef,因此不必再调用它。<br>&nbsp;&nbsp;但两者返回的IUnknow接口和一般接口，用完后都需要调用Release来释放。<br>&nbsp;&nbsp;一般而言，每当复制一个接口的指针时，都应该相应的增加引用计数。<br>&nbsp;&nbsp;&nbsp;IUnknown* pIUnknown=CreateInstance();<br>&nbsp;&nbsp;&nbsp;IX * pIX=NULL;<br>&nbsp;&nbsp;&nbsp;HRESULT hr= pIUnknown-&gt;QueryInterface(IID_IX,(void **)&amp;pIX);<br>&nbsp;&nbsp;&nbsp;pIUnknown-&gt;Release();<br>&nbsp;&nbsp;&nbsp;if(SUCCEEDED(hr))<br>&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;pIX-&gt;Fx();&nbsp;&nbsp;&nbsp;&nbsp;//Fx()为功能函数<br>&nbsp;&nbsp;&nbsp;&nbsp;IX * pIX2=pIX;&nbsp;&nbsp; //复制指针，即增加了一个使用组件(的接口)的可能，<br>&nbsp;&nbsp;&nbsp;&nbsp;pIX2-&gt;AddRef();&nbsp; //所以要增加计数，并在使用完之后release<br>&nbsp;&nbsp;&nbsp;&nbsp;pIX2-&gt;Fx();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;pIX2-&gt;Release(); //<br>&nbsp;&nbsp;&nbsp;&nbsp;pIX-&gt;Release();&nbsp; <br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;//上面代码中，作为复制指针pIX2，其生存周期与pIX相同，即，在pIX Release之前pIX2就已经不再使用了，<br>&nbsp;&nbsp;&nbsp;pIX保证了组件使用安全的前提下，pIX不用AddRef和Release是肯定没问题的。<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;但有时很难判断某些没有加上AddRef和Release的调用是不是正确，是优化还是程序错误。一般用智能来封装<br>&nbsp;&nbsp;&nbsp;引用计数，从而解决这个问题。(智能指针)<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;组件可以对其每一个接口分别维护一个引用计数，也可以对整个组件维护单个的引用计数。原则上选择了为每一个<br>&nbsp;&nbsp;&nbsp;接口单独维护一个引用计数而不是针对整个维护计数，原因，一，使程序调试更方便，二，支持系统资源的按需获取。<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;(2)AddRef\Release 实现<br>&nbsp;&nbsp;&nbsp;主要是改变成员变量m_cRef的数值。AddRef增加其数值，Release减小数值，并在此值为0时将组件删除。<br>&nbsp;&nbsp;&nbsp;简单实现：<br>&nbsp;&nbsp;&nbsp;&nbsp;ULONG _stdcall AddRef()<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return ++m_cRef;//return InterlockIncrement(&amp;m_cRef);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;ULONG _stdcall Release()<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(--m_cRef==0)//if(InterlockDecrement(&amp;m_cRef)==0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete this;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return m_cRef;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;一般用InterlockIncrement和InterlockDecrement来实现AddRef\Release; 可以确保同一时间只有同一线程来访问成员变量。<br>&nbsp; 3)引用计数的优化原则<br>&nbsp; &nbsp;&nbsp;就像(1)中例子，pIX能保障在pIX2生命周期内，组件肯定会在内存内存留。即，那些生命周期嵌套在引用同一接口的指针的生命周期之内时，外层的已有引用计数，内层的就可以不要了。<br>&nbsp; &nbsp;&nbsp;注意那些生命周期重叠的指针。<br>&nbsp; &nbsp;&nbsp;(1)输出参数原则<br>&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;如果接口指针以函数返回值或者以传出参数传出，那么在函数内部，返回参数前调用AddRef.<br>&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;例 QueryInterface/CreateInstance;<br>&nbsp; &nbsp;&nbsp;(2)输入参数原则<br>&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;若接口指针作为参数传递给一个函数，该函数不修改也将其返回调用者，此时无需调用AddRef\Release例：<br>&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void foo(pIX *pIX)<br>&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pIX-&gt;Fx();<br>&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;因为函数的生命周期嵌套在调用者的生命周期之内的。<br>&nbsp; &nbsp;&nbsp;(3)输入输出参数原则<br>&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;对于传递进来的接口指针，必须在给他附另外一个接口指针之前调用release；返回之前，还必须对输出参数指向的新接口调用AddRef;<br>&nbsp; 4)局部变量原则<br>&nbsp; &nbsp;&nbsp;它们是在函数的生存周期内才存在，因此不需要调用AddRef\Release<br>&nbsp; 5)全局变量原则<br>&nbsp; &nbsp;&nbsp;在传递给另一个函数之前，必须调用AddRef.<br>&nbsp; 6)不确定的情况<br>&nbsp; &nbsp;&nbsp;此时需要调用AddRef\Release 以防万一<br><img src ="http://www.cppblog.com/yearner/aggbug/63500.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yearner/" target="_blank">(Leyn)顽主</a> 2008-10-08 21:57 <a href="http://www.cppblog.com/yearner/archive/2008/10/08/63500.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《C++高效编程》学习笔记（1）</title><link>http://www.cppblog.com/yearner/archive/2008/10/01/63125.html</link><dc:creator>(Leyn)顽主</dc:creator><author>(Leyn)顽主</author><pubDate>Wed, 01 Oct 2008 06:53:00 GMT</pubDate><guid>http://www.cppblog.com/yearner/archive/2008/10/01/63125.html</guid><wfw:comment>http://www.cppblog.com/yearner/comments/63125.html</wfw:comment><comments>http://www.cppblog.com/yearner/archive/2008/10/01/63125.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/yearner/comments/commentRss/63125.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yearner/services/trackbacks/63125.html</trackback:ping><description><![CDATA[1.尽量用const 和inline 而不用#define<br>&nbsp; 1)例：#define ASPECT_RATIO 1.653<br>&nbsp;&nbsp; 在源码进入编译器之前，预编译指令会被处理器去掉，直接用1.653代替ASPECT_RATIO，如果涉及到这个常量的代码出错，若想由1.653追踪到原指令会很困难<br>&nbsp;&nbsp; 所以，这种情况下一般用const double ASPECT_RATIO=1.653代替。<br>&nbsp;&nbsp; 定义指针时，需要把指针和指向的变量都定义成const<br>&nbsp;&nbsp; const char * const authorName ="YLang"&nbsp;&nbsp; <br>&nbsp;&nbsp; <br>&nbsp; 2)有些编译器，类内只允许初始化整数类型（int,bool,char）还只能是常量<br>&nbsp;&nbsp; 若在类内分开声明数组和数组大小，为避免某些编译器的不足，采用enum枚举的方式<br>&nbsp;&nbsp; enum{NUM_TURNS=5};//直接采用 const NUM_TURNS=5; 对于某些禁止此行为的编译器来说，会出现编译错误；<br>&nbsp;&nbsp; int scores[NUM_TURNS];<br>&nbsp; <br>&nbsp; 3)#define 宏的用法<br>&nbsp;&nbsp; 例：最大值算法<br>&nbsp;&nbsp;&nbsp;&nbsp; #define&nbsp; max(a,b) ((a)&gt;(b)?(a):(b))//每个参数必须加括号<br>&nbsp;&nbsp;&nbsp;&nbsp; 在遇到自加时，表现了很大的不稳定性。<br>&nbsp;&nbsp;&nbsp;&nbsp; int a=5,b=0;<br>&nbsp;&nbsp;&nbsp;&nbsp; max(++a,b);//a的值增加了2次<br>&nbsp;&nbsp;&nbsp;&nbsp; max(++a,b+10);//a的值只增加了1次<br>&nbsp;&nbsp; 采用inline函数来替换该宏。&nbsp;&nbsp; <br>&nbsp;&nbsp; inline int max(int a,int b) {return a&gt;b?a:b;}<br>&nbsp;&nbsp; template&lt;class T&gt;<br>&nbsp;&nbsp; inline const T&amp; max(const T&amp; a, const T&amp; b)<br>&nbsp;&nbsp; { return a&gt;b?a:b;}<br>&nbsp;&nbsp; <br>2.尽量用&lt;iostream&gt;而不是&lt;stdio.h&gt;<br>&nbsp;&nbsp; scanf/printf 不是安全类型，没有扩展性，并且把要读写的变量和控制读写格式信息分开。<br>&nbsp;&nbsp; 重载运算符&lt;&lt; 弥补了他们的缺点。<br>&nbsp;&nbsp; &lt;iostream&gt;可移植性可扩展性较高，库类有构造函数；&lt;stdio.h&gt;库类没有构造函数<br>&nbsp;&nbsp; #include &lt;iostream&gt; 和#include &lt;iostream.h&gt;的区别<br>&nbsp;&nbsp; 前者得到的是置于std名字空间下的元素，后者是同样的元素，但是全局空间里，会造成命名冲突。<br>&nbsp;&nbsp; <br>3.尽量用new和delete而不是malloc 和free<br>&nbsp;前者会创建/删除对象，同时调用构造/析构函数；后者仅创建/删除空间，没有调用构造/析构函数；<br>&nbsp;<br>4.C++注释风格<br>&nbsp;尽量不要用/* */<br>&nbsp;<br>5.new和delete要对应相同的形式<br>&nbsp;new数组用了[] ，delete也必须用[];<br>&nbsp;如果要删除指针指向的数组空间需要用delete[];<br>&nbsp;<br>6.尽量在析构函数里对指针成员调用delete<br>&nbsp;除非类成员最初用了new，否则是不用在析构里用delete的。<br>&nbsp;或者用智能指针来代替(C++标准库auto_ptr)\<br>&nbsp;<br>7.预先准备好内存不足的情况<br>&nbsp;考虑到当new一个对象时，理论上可能会发生无法完成内存分配而抛出异常的情况。<br>&nbsp;C的做法是定义宏来分配内存并检查分配是否成功。<br>&nbsp;这种宏的C++再现：<br>&nbsp;#define NEW(PTR,TYPE)<br>&nbsp;try {(PTR)= new TYPE;}<br>&nbsp; catch(std::bad_alloc&amp;){assert(0);}<br>&nbsp;//说明：<br>&nbsp;//1)assert检查传给它的表达式是否为非零，如果不是非0，发出一条错误信息并调用abort. <br>&nbsp;// 而assert只是在调试状态(没有定义 NDEBUGE)下才会起作用，产品发布时(定义 NDEBUGE)assert什么都不做。 <br>&nbsp;//2)没有考虑到new的多种形式: new T;new T(constructor argument);new T[size];<br>&nbsp;所以一般不用这种方案<br>&nbsp;简单的方法：制定一错误处理函数，在抛出异常前调用。<br>&nbsp;在头文件&lt;new&gt;中,<br>&nbsp;typedef void (* new_handler)();<br>&nbsp;new_handler set_new_handler()(new_handler p) throw();<br>&nbsp;在调用new之前，使用set_new_handler来设定错误处理函数，传入参数为函数指针。<br>&nbsp;例：<br>&nbsp; void onMemoryError(){......}//invoke before throwing the expection;<br>&nbsp; int mail()<br>&nbsp; {<br>&nbsp;&nbsp; set_new_handler(onMemoryError);<br>&nbsp;&nbsp; int *pBigMemory=new int[100000];<br>&nbsp; }<br>&nbsp;C++ 中处理机制：<br>&nbsp; 设定处理函数为全局，在set_new_handler安装自定义处理函数之前保存原有函数。<br>&nbsp; 分配内存，若失败则抛出异常，返回之前恢复原处理函数。<br>&nbsp; void * X::operator new(size_t size)<br>&nbsp; {<br>&nbsp;&nbsp; new_handler globalHandler = // 安装X 的new_handler<br>&nbsp;&nbsp; std::set_new_handler(currentHandler);<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp; void *memory;<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp; try<br>&nbsp;&nbsp;&nbsp;&nbsp; { // 尝试分配内存<br>&nbsp;&nbsp;&nbsp;&nbsp; memory = ::operator new(size);<br>&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp; catch (std::bad_alloc&amp;)<br>&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp; // 恢复旧的new_handler<br>&nbsp;&nbsp;&nbsp;&nbsp; std::set_new_handler(globalHandler);<br>&nbsp;&nbsp;&nbsp;&nbsp; throw; // 抛出异常<br>&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp; std::set_new_handler(globalHandler); // 恢复旧的new_handler<br>&nbsp;&nbsp; return memory;<br>&nbsp; }<br><br><img src ="http://www.cppblog.com/yearner/aggbug/63125.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yearner/" target="_blank">(Leyn)顽主</a> 2008-10-01 14:53 <a href="http://www.cppblog.com/yearner/archive/2008/10/01/63125.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>COM 学习笔记（1）</title><link>http://www.cppblog.com/yearner/archive/2008/07/22/56882.html</link><dc:creator>(Leyn)顽主</dc:creator><author>(Leyn)顽主</author><pubDate>Tue, 22 Jul 2008 10:50:00 GMT</pubDate><guid>http://www.cppblog.com/yearner/archive/2008/07/22/56882.html</guid><wfw:comment>http://www.cppblog.com/yearner/comments/56882.html</wfw:comment><comments>http://www.cppblog.com/yearner/archive/2008/07/22/56882.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yearner/comments/commentRss/56882.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yearner/services/trackbacks/56882.html</trackback:ping><description><![CDATA[<p class="MsoNormal"><span lang="EN-US">COM </span><span style="font-family: 宋体;">学习笔记</span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">QueryInterface</span><span style="font-family: 宋体;">函数</span></p>
<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">主要用于</span><span lang="EN-US">COM</span><span style="font-family: 宋体;">接口的查询。它是</span><span lang="EN-US">COM</span><span style="font-family: 宋体;">接口定义</span><span lang="EN-US">IUnknown</span><span style="font-family: 宋体;">的成员函数，客户可以调用</span><span lang="EN-US">QueryInterface</span><span style="font-family: 宋体;">来决定组件是否支持某个特定的接口。</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">组件</span><span lang="EN-US">COM</span><span style="font-family: 宋体;">接口都是从</span><span lang="EN-US">IUnkonwn</span><span style="font-family: 宋体;">接口继承而来，任何一个接口都可以用</span><span lang="EN-US">IUnknown</span><span style="font-family: 宋体;">的成员</span><span lang="EN-US">QueryInterface</span><span style="font-family: 宋体;">来获取它所支持的其它接口。</span></p>
<p class="MsoNormal" style="text-indent: 21pt;"><span lang="EN-US">1</span><span style="font-family: 宋体;">）定义：</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>HRESULT
_stdcall QueryInterface(const IID&amp; iid,void ** ppv);</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">第一个参数十所需接口的标识，是一个接口标识符</span><span lang="EN-US">IID</span><span style="font-family: 宋体;">结构。</span> <span style="font-family: 宋体;">第二个参数存放所请求接口指针的地址。</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;</span><span>&nbsp;&nbsp;&nbsp;&nbsp; </span>2</span><span style="font-family: 宋体;">）使用过程：</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">假定已有一个指向</span><span lang="EN-US">IUnknown</span><span style="font-family: 宋体;">的指针</span><span lang="EN-US">pI</span><span style="font-family: 宋体;">，为知道相应的组件是否支持某个特定的接口，调用</span><span lang="EN-US">QueryInterface</span><span style="font-family: 宋体;">，传给它一个接口标识符。若成功返回，那就是可以使用它返回的指针。</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US">Void
foo(IUnknown * pI)</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US">{</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>IX *pIX=NULL;</span></p>
<p class="MsoNormal" style="margin-left: 20.25pt; text-indent: 21.75pt;"><span lang="EN-US">HRESULT hr=pI-&gt;QueryInterface(IID_IX,(void **)&amp;pIX);</span></p>
<p class="MsoNormal" style="margin-left: 20.25pt; text-indent: 21.75pt;"><span lang="EN-US">If(SUCCEEDED(hr))</span></p>
<p class="MsoNormal" style="margin-left: 41.25pt; text-indent: 21.75pt;"><span lang="EN-US">pIX-&gt;Fx();</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US">}</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span style="font-family: 宋体;">该函数用于查询</span><span lang="EN-US">pI</span><span style="font-family: 宋体;">是否支持由</span><span lang="EN-US">IID_IX</span><span style="font-family: 宋体;">所标识的接口。</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US">IUnknown</span><span style="font-family: 宋体;">的继承不是虚拟基类。</span><span lang="EN-US">COM</span><span style="font-family: 宋体;">接口不能按照虚拟方式继承它。</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US">3</span><span style="font-family: 宋体;">）实现：</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US">Interface IX</span><span style="font-family: 宋体;">：</span><span lang="EN-US">IUnknown{/**/}</span><span style="font-family: 宋体;">；</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US">Interface IY</span><span style="font-family: 宋体;">：</span><span lang="EN-US">IUnknown{/**/}</span><span style="font-family: 宋体;">；</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US">Class CA</span><span style="font-family: 宋体;">：</span><span lang="EN-US">public IX,public IY{/**/};</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span style="font-family: 宋体;">主要通过判断标识符是否为</span><span lang="EN-US">CA</span><span style="font-family: 宋体;">的支持类型，来判断是否为存在在</span><span lang="EN-US">CA</span><span style="font-family: 宋体;">中的</span><span lang="EN-US">COM</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US">HRESULT
_stdcall CA:;QueryInterface(const IID &amp;iid,void **ppv)</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US">{</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>If(iid==IID_IUnknown)</span></p>
<p class="MsoNormal" style="margin-left: 20.25pt; text-indent: 21.75pt;"><span lang="EN-US">{</span></p>
<p class="MsoNormal" style="margin-left: 20.25pt; text-indent: 21.75pt;"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>*ppv=static_cast&lt;IX
*&gt;(this);</span></p>
<p class="MsoNormal" style="margin-left: 20.25pt; text-indent: 21.75pt;"><span lang="EN-US">}</span></p>
<p class="MsoNormal" style="margin-left: 20.25pt; text-indent: 21.75pt;"><span lang="EN-US">Else if(iid==IID_IX)</span></p>
<p class="MsoNormal" style="margin-left: 20.25pt; text-indent: 21.75pt;"><span lang="EN-US">{</span></p>
<p class="MsoNormal" style="margin-left: 20.25pt; text-indent: 21.75pt;"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>*ppv=static_cast&lt;IX*&gt;(this);</span></p>
<p class="MsoNormal" style="margin-left: 20.25pt; text-indent: 21.75pt;"><span lang="EN-US">}</span></p>
<p class="MsoNormal" style="margin-left: 20.25pt; text-indent: 21.75pt;"><span lang="EN-US">Else if (iid==IID_IY)</span></p>
<p class="MsoNormal" style="margin-left: 20.25pt; text-indent: 21.75pt;"><span lang="EN-US">{</span></p>
<p class="MsoNormal" style="margin-left: 20.25pt; text-indent: 21.75pt;"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>*ppv=static_cast&lt;IY*&gt;(this);</span></p>
<p class="MsoNormal" style="margin-left: 20.25pt; text-indent: 21.75pt;"><span lang="EN-US">}</span></p>
<p class="MsoNormal" style="margin-left: 20.25pt; text-indent: 21.75pt;"><span lang="EN-US">Else </span></p>
<p class="MsoNormal" style="margin-left: 20.25pt; text-indent: 21.75pt;"><span lang="EN-US">{</span></p>
<p class="MsoNormal" style="margin-left: 20.25pt; text-indent: 21.75pt;"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>*ppv=NULL;</span></p>
<p class="MsoNormal" style="margin-left: 20.25pt; text-indent: 21.75pt;"><span lang="EN-US">Return E_NOINTERFACE;</span></p>
<p class="MsoNormal" style="margin-left: 20.25pt; text-indent: 21.75pt;"><span lang="EN-US">}</span></p>
<p class="MsoNormal" style="margin-left: 20.25pt; text-indent: 21.75pt;"><span lang="EN-US">Static_cast&lt;IUnknown*&gt;(*ppv)-&gt;AddRef();</span></p>
<p class="MsoNormal" style="margin-left: 20.25pt; text-indent: 21.75pt;"><span lang="EN-US">Return S_OK;</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US">}</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US">4</span><span style="font-family: 宋体;">）关于其中的类型转换</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US"><span>&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">程序中若将</span><span lang="EN-US">this</span><span style="font-family: 宋体;">指针直接转换成</span><span lang="EN-US">IUnknown*</span><span style="font-family: 宋体;">是不明确的。因为存在两个基类接口，需要指明是转换向哪一个接口的</span><span lang="EN-US">IUnknown</span><span style="font-family: 宋体;">。</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US">Static_cast&lt;IUnknown*&gt;
(static_cast&lt;IX *&gt;(this))</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;,&quot;serif&quot;;" lang="EN-US"><!--[if gte vml 1]><v:shapetype id="_x0000_t75"
coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe"
filled="f" stroked="f">
<v:stroke joinstyle="miter"/>
<v:formulas>
<v:f eqn="if lineDrawn pixelLineWidth 0"/>
<v:f eqn="sum @0 1 0"/>
<v:f eqn="sum 0 0 @1"/>
<v:f eqn="prod @2 1 2"/>
<v:f eqn="prod @3 21600 pixelWidth"/>
<v:f eqn="prod @3 21600 pixelHeight"/>
<v:f eqn="sum @0 0 1"/>
<v:f eqn="prod @6 1 2"/>
<v:f eqn="prod @7 21600 pixelWidth"/>
<v:f eqn="sum @8 21600 0"/>
<v:f eqn="prod @7 21600 pixelHeight"/>
<v:f eqn="sum @10 21600 0"/>
</v:formulas>
<v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"/>
<o:lock v:ext="edit" aspectratio="t"/>
</v:shapetype><v:shape id="_x0000_i1025" type="#_x0000_t75" style="'width:414.75pt;
height:235.5pt'">
<v:imagedata src="file:///C:\DOCUME~1\LEYANG~1.ETH\LOCALS~1\Temp\msohtmlclip1\01\clip_image001.png"
o:title=""/>
</v:shape><![endif]--><!--[if !vml]--><img  src="file:///C:/DOCUME~1/LEYANG~1.ETH/LOCALS~1/Temp/msohtmlclip1/01/clip_image002.jpg" v:shapes="_x0000_i1025" height="314" width="553"><!--[endif]--></span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span style="font-family: 宋体;">在类型转换时，</span><span lang="EN-US">CA</span><span style="font-family: 宋体;">按照顺序存放它的基类接口及其实现，其</span><span lang="EN-US">this</span><span style="font-family: 宋体;">指针可以用</span><span lang="EN-US">IX</span><span style="font-family: 宋体;">代替（地址值相同）。</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span style="font-family: 宋体;">而</span><span lang="EN-US">IY</span><span style="font-family: 宋体;">则需要</span><span lang="EN-US">CA</span><span style="font-family: 宋体;">的基址加上偏移址。</span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p>&nbsp;</o:p></span></p><img src ="http://www.cppblog.com/yearner/aggbug/56882.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yearner/" target="_blank">(Leyn)顽主</a> 2008-07-22 18:50 <a href="http://www.cppblog.com/yearner/archive/2008/07/22/56882.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>