﻿<?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++博客-eXile 的专栏-随笔分类-C/C++</title><link>http://www.cppblog.com/eXile/category/7018.html</link><description /><language>zh-cn</language><lastBuildDate>Thu, 28 Jan 2010 22:25:02 GMT</lastBuildDate><pubDate>Thu, 28 Jan 2010 22:25:02 GMT</pubDate><ttl>60</ttl><item><title>说说C++智能指针(2): 标准库中的智能指针</title><link>http://www.cppblog.com/eXile/archive/2009/11/16/101062.html</link><dc:creator>eXile</dc:creator><author>eXile</author><pubDate>Mon, 16 Nov 2009 05:57:00 GMT</pubDate><guid>http://www.cppblog.com/eXile/archive/2009/11/16/101062.html</guid><wfw:comment>http://www.cppblog.com/eXile/comments/101062.html</wfw:comment><comments>http://www.cppblog.com/eXile/archive/2009/11/16/101062.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/eXile/comments/commentRss/101062.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/eXile/services/trackbacks/101062.html</trackback:ping><description><![CDATA[

<p><span style="FONT-FAMILY: courier new; FONT-SIZE: 12pt">&nbsp; <span style="FONT-FAMILY: Courier">使用智能指针是C++中常用的管理内存的方式。关于智能指针的设计，各路C++高手也是各展神通。<br><br>&nbsp; 在1994年. Greg Colvin向C++标准委员会提出了自己设计的智能指针：auto_ptr和counted_ptr。auto_ptr实现基本的RAII管理，不可复制；counted_ptr采用引用计数实现了一个可复制的智能指针。两者用于不同的场合。<br>&nbsp; 但是标准委员会最终只通过了auto_ptr，并且对auto_ptr加入了一个古怪的&#8220;所有权转移&#8221;语义。后来auto_ptr和counted_ptr进入了Boost C++ 库，改名为scoped_ptr和shared_ptr。<br>&nbsp;&nbsp;<br>&nbsp; std::auto_ptr只所以设计为可拷贝的，也许是出于以下考虑，比如下例函数：</span></span></p>
<font size="4">
<div style="border-left-color: rgb(204, 204, 204); padding-bottom: 4px; background-color: rgb(238, 238, 238); padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; padding-top: 4px; "><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;f1(</span><span style="COLOR: #0000ff">object</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;ptr);<br></span><span style="COLOR: #0000ff">object</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;f2();</span></div>
</font><p><font size="4">&nbsp; </font><span style="FONT-SIZE: 12pt">&nbsp;f1中的参数所指向的对象应该由谁来删除呢？调用者还是被调用者？如果不看程序文档的话，无法知道这一点。f2函数也存在同样的问题。<br><br>&nbsp;&nbsp; 用auto_ptr可以消除这种歧义性：</span></p>
<font size="4">
<div style="border-left-color: rgb(204, 204, 204); padding-bottom: 4px; background-color: rgb(238, 238, 238); padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; padding-top: 4px; "><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;f1(auto_ptr</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">object</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;ptr);<br>auto_ptr</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">object</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;f2();</span></div>
</font><p><font size="4">&nbsp;&nbsp;<br></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="FONT-FAMILY: courier new">尽管如此，auto_ptr的&#8220;所有权转移&#8221;语义还是会带来副作用，因为会修改原值的常量拷贝违背了一般的设计原则，它也许会在你意想不到的情况下就把对象转移了。它也不能用于标准容器中。<br>&nbsp;&nbsp; 所以auto_ptr在新的标准库已经不再推荐使用。取而代之的是unique_ptr。unique_ptr与auto_ptr类似，但限制了auto_ptr的拷贝行为。同时，像上面举的例子一样，unique_ptr可以作为函数的参数和返回值使用。这是因为C++增加了一个新的特征：右值引用。<br><br>&nbsp;&nbsp; shared_ptr也进入了标准库。对于引用计数的智能指针而言，循环引用是一个大问题。标准库为此把shared_ptr定义为强引用指针，它还实现了一个弱引用指针weak_ptr。显然，标准库并没有从根本上解决循环引用的问题，它把这个问题交给了程序员。在一个简单的系统中，你可以区分使用shared_ptr和weak_ptr，以此来避免出现循环引用。但是在一个大的对象系统中，有时还是容易出错。循环引用的问题，严重减弱了shared_ptr的可用性。<br><br>&nbsp;&nbsp; 那么能不能自动检测是否出现循环引用呢？事实上，对于shared_ptr这种使用非侵入式策略实现的智能指针，是很难实现自动检测的。但是如果采用侵入式设计，我们可以引入一些接口，来解决这个问题。循环引用的检测，实际上是图论中的回路检测问题。<br></span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 本文由<a style="FONT-SIZE: 12pt" title="eXile" href="http://www.cppblog.com/eXile/">eXile</a><span style="FONT-SIZE: 12pt">&nbsp;原创，转载请表明原贴地址。&nbsp;</span><a href="http://www.cppblog.com/eXile/">http://www.cppblog.com/eXile/</a>。</p><img src ="http://www.cppblog.com/eXile/aggbug/101062.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eXile/" target="_blank">eXile</a> 2009-11-16 13:57 <a href="http://www.cppblog.com/eXile/archive/2009/11/16/101062.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>说说C++智能指针(1): 关于shared_ptr</title><link>http://www.cppblog.com/eXile/archive/2009/11/02/99995.html</link><dc:creator>eXile</dc:creator><author>eXile</author><pubDate>Mon, 02 Nov 2009 09:38:00 GMT</pubDate><guid>http://www.cppblog.com/eXile/archive/2009/11/02/99995.html</guid><wfw:comment>http://www.cppblog.com/eXile/comments/99995.html</wfw:comment><comments>http://www.cppblog.com/eXile/archive/2009/11/02/99995.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/eXile/comments/commentRss/99995.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/eXile/services/trackbacks/99995.html</trackback:ping><description><![CDATA[<span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span>&nbsp;&nbsp; shared_ptr是新的标准库的一个主要成员，作为一个非嵌入式的智能指针，其设计可谓已经是绞尽脑汁。当然，还有很多人对它提出了不满。没有完美的设计，只有合适的设计。<br><br>1. </span><span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span>shared_ptr最大的特点是接口的简单性与实现的灵活性。<br>&nbsp;&nbsp;&nbsp; 对于shared_ptr&lt;Object&gt;,object的内存管理是可定制的，甚至可以定制引用计数结点的内存分配，以满足对内存有特殊要求的情况。而这一切，都被</span><span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span>Object的实现者隐藏起来，</span><span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span></span><span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span>使用Object的客户类是不用关心的。这和以前标准库的组件实现策略有些不同。比如说, vector&lt;int, A1&gt;和vector&lt;int, A2&gt;，由于内存分配策略的不同，而变成类型的不同，造成接口的改变。</span><span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span>这一点在shared_ptr的设计时被避免了，当然以一定的性能代价。shared_ptr作为C++面向对象设计的一个重要组件，</span><span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span>接口的简单性是很重要的，必须要有</span><span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span></span><span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span>接口和实现的分离。与此相似的还有tr1::function的设计。<br><br>2.在同一体系中，各种类型的智能指针可以互相转换。<br><br>&nbsp;&nbsp; 如下例：<br><br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;Object&nbsp;:&nbsp;InterfaceA,&nbsp;InterfaceB&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;MemberA&nbsp;memberA;<br>};<br><br><br>shared_ptr</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">Object</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;obj(</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;Object);<br>shared_ptr</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">InterfaceA</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;a&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;obj;<br>shared_ptr</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">InterfaceB</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;b&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;obj;<br></span><span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span><span style="COLOR: #000000">shared_ptr</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">Object</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;p&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;static_pointer_cast</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">Object</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">(b);<br></span></span><span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span><span style="COLOR: #000000">shared_ptr</span><span style="COLOR: #000000">&lt;void</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;p2 </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> obj;</span></span><span style="COLOR: #000000"><br><br></span></div>
<br>&nbsp; 甚至还可以取得数据成员的智能指针：<br><br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #000000">shared_ptr</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">Object</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;obj(</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;Object);<br>shared_ptr</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">MemberA</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;memberA(obj,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">obj</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">memberA);</span></div>
<br><br>&nbsp; 再来说说shared_ptr的缺点。<br></span><span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span><br>1.对于使用引用计数的智能指针来说，必须要小心出现循环引用。<br>&nbsp;&nbsp;&nbsp;&nbsp; 在重度使用</span><span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span>shared_ptr的系统中，你必须一开始就明确类与类的关系，以决定哪里使用</span><span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span>shared_ptr，哪里使用</span>weak_ptr，否则就会出现内存泄露。而<span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span>shared_ptr的接口</span><span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span>转换</span><span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span>的灵活性，也很容易导致</span><span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span>智能指针被滥用。</span>内存自动管理的问题并没有得到解决，它只是被转移了。<br><br><span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span>2.shared_ptr使用非嵌入式设计，这样可以使用于基本类型，比如 shared_ptr&lt;int&gt;。但是根据个人经验，这种情况在很少使用。大部分情况还是使用自己设计的类。这有一个问题，就是没有很方便的办法实现this指针和</span><span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span>智能指针的转换。标准库中提供了enable_shared_from_this类来解决这个问题。但这</span>已经使所谓的<span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span>非嵌入式设计徒有虚名</span><span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span></span>。而假如一开始采用<span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span>嵌入式设计的话，则在性能代价和多线程设计方面具有更大的灵活性。</span><br><span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span><br></span>
<img src ="http://www.cppblog.com/eXile/aggbug/99995.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eXile/" target="_blank">eXile</a> 2009-11-02 17:38 <a href="http://www.cppblog.com/eXile/archive/2009/11/02/99995.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>最简单的foreach实现(VC &amp; GCC)</title><link>http://www.cppblog.com/eXile/archive/2009/05/08/82201.html</link><dc:creator>eXile</dc:creator><author>eXile</author><pubDate>Thu, 07 May 2009 17:25:00 GMT</pubDate><guid>http://www.cppblog.com/eXile/archive/2009/05/08/82201.html</guid><wfw:comment>http://www.cppblog.com/eXile/comments/82201.html</wfw:comment><comments>http://www.cppblog.com/eXile/archive/2009/05/08/82201.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/eXile/comments/commentRss/82201.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/eXile/services/trackbacks/82201.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 对于VC 和GCC 分别用最简单方法实现了foreach遍历。&nbsp;&nbsp;<a href='http://www.cppblog.com/eXile/archive/2009/05/08/82201.html'>阅读全文</a><img src ="http://www.cppblog.com/eXile/aggbug/82201.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eXile/" target="_blank">eXile</a> 2009-05-08 01:25 <a href="http://www.cppblog.com/eXile/archive/2009/05/08/82201.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[T] 利用QT进行web与本地混合应用开发 </title><link>http://www.cppblog.com/eXile/archive/2009/03/09/75997.html</link><dc:creator>eXile</dc:creator><author>eXile</author><pubDate>Mon, 09 Mar 2009 08:41:00 GMT</pubDate><guid>http://www.cppblog.com/eXile/archive/2009/03/09/75997.html</guid><wfw:comment>http://www.cppblog.com/eXile/comments/75997.html</wfw:comment><comments>http://www.cppblog.com/eXile/archive/2009/03/09/75997.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/eXile/comments/commentRss/75997.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/eXile/services/trackbacks/75997.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Qt提供了本地 C++对象与JavaScript的无缝集成，是进行本地与web混合应用开发的理想平台。&nbsp;&nbsp;<a href='http://www.cppblog.com/eXile/archive/2009/03/09/75997.html'>阅读全文</a><img src ="http://www.cppblog.com/eXile/aggbug/75997.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eXile/" target="_blank">eXile</a> 2009-03-09 16:41 <a href="http://www.cppblog.com/eXile/archive/2009/03/09/75997.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个小疑问：C++头文件中的静态全局变量</title><link>http://www.cppblog.com/eXile/archive/2009/01/09/71567.html</link><dc:creator>eXile</dc:creator><author>eXile</author><pubDate>Fri, 09 Jan 2009 03:42:00 GMT</pubDate><guid>http://www.cppblog.com/eXile/archive/2009/01/09/71567.html</guid><wfw:comment>http://www.cppblog.com/eXile/comments/71567.html</wfw:comment><comments>http://www.cppblog.com/eXile/archive/2009/01/09/71567.html#Feedback</comments><slash:comments>18</slash:comments><wfw:commentRss>http://www.cppblog.com/eXile/comments/commentRss/71567.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/eXile/services/trackbacks/71567.html</trackback:ping><description><![CDATA[&nbsp; 一般来说，静态全局变量只应该定义在实现文件中，但有时由于一些特殊的目的，也可能定义在头文件中。比如在有些标准库的实现中，就用这种方法来初始化标准流cin, cout，或者在在tr1库中，也用这种方法来定义占位符。每一个包含该头文件的实现文件中都拥有该变量的一份拷贝，这些变量放在运行体的data段或者bss段。<br>&nbsp;&nbsp; 比如下面这个变量定义在一个头文件中：<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: #008000;"></span><span style="color: #008000;"></span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;data[</span><span style="color: #000000;">1024</span><span style="color: #000000;">*</span><span style="color: #000000;">1024</span><span style="color: #000000;">];</span></div>
&nbsp;&nbsp; 我把这个文件同时包含在几个cpp文件中，按我的理解，这个程序占用的内存应该显著增大，但是，从实际运行结果来看，并没有变化，生成的exe文件大小也没有变化，这是因为延迟加载呢，还是被编译器优化掉了？有没有明白的达人解释一下。<br><br><br> <img src ="http://www.cppblog.com/eXile/aggbug/71567.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eXile/" target="_blank">eXile</a> 2009-01-09 11:42 <a href="http://www.cppblog.com/eXile/archive/2009/01/09/71567.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用ICE实现一个简单的聊天室</title><link>http://www.cppblog.com/eXile/archive/2009/01/04/ice.html</link><dc:creator>eXile</dc:creator><author>eXile</author><pubDate>Sat, 03 Jan 2009 17:32:00 GMT</pubDate><guid>http://www.cppblog.com/eXile/archive/2009/01/04/ice.html</guid><wfw:comment>http://www.cppblog.com/eXile/comments/71099.html</wfw:comment><comments>http://www.cppblog.com/eXile/archive/2009/01/04/ice.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/eXile/comments/commentRss/71099.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/eXile/services/trackbacks/71099.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 聊天室是一种典型的网络应用，这个程序演示了ICE框架的基本结构。&nbsp;&nbsp;<a href='http://www.cppblog.com/eXile/archive/2009/01/04/ice.html'>阅读全文</a><img src ="http://www.cppblog.com/eXile/aggbug/71099.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eXile/" target="_blank">eXile</a> 2009-01-04 01:32 <a href="http://www.cppblog.com/eXile/archive/2009/01/04/ice.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用scons编译Qt应用</title><link>http://www.cppblog.com/eXile/archive/2008/10/21/qt-cons.html</link><dc:creator>eXile</dc:creator><author>eXile</author><pubDate>Tue, 21 Oct 2008 15:48:00 GMT</pubDate><guid>http://www.cppblog.com/eXile/archive/2008/10/21/qt-cons.html</guid><wfw:comment>http://www.cppblog.com/eXile/comments/64663.html</wfw:comment><comments>http://www.cppblog.com/eXile/archive/2008/10/21/qt-cons.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/eXile/comments/commentRss/64663.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/eXile/services/trackbacks/64663.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 一般推荐qmake来编译Qt应用程序, qmake用起来也很简单，但是用scons更简单, 更灵活。&nbsp;&nbsp;<a href='http://www.cppblog.com/eXile/archive/2008/10/21/qt-cons.html'>阅读全文</a><img src ="http://www.cppblog.com/eXile/aggbug/64663.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eXile/" target="_blank">eXile</a> 2008-10-21 23:48 <a href="http://www.cppblog.com/eXile/archive/2008/10/21/qt-cons.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Google C++ Testing Framework Primer(zt)</title><link>http://www.cppblog.com/eXile/archive/2008/07/21/56738.html</link><dc:creator>eXile</dc:creator><author>eXile</author><pubDate>Mon, 21 Jul 2008 03:35:00 GMT</pubDate><guid>http://www.cppblog.com/eXile/archive/2008/07/21/56738.html</guid><wfw:comment>http://www.cppblog.com/eXile/comments/56738.html</wfw:comment><comments>http://www.cppblog.com/eXile/archive/2008/07/21/56738.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/eXile/comments/commentRss/56738.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/eXile/services/trackbacks/56738.html</trackback:ping><description><![CDATA[<div class="postbody clearfix">
<p><strong><span class="hilite1"><span class="hilite1">Google</span></span> C++ <span class="hilite2"><span class="hilite2">Test</span></span>ing Framework Primer</strong></p>
<p><br></p>
<p><br></p>
<p>翻译：<a  href="http://rayleex.spaces.live.com/blog/cns%21C32DFA3924AF2128%21218.entry" target="_blank">Ray Li </a>(<a  href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#114;&#97;&#121;&#46;&#108;&#101;&#101;&#120;&#64;&#103;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;">ray.leex@gmail.com</a>)
<br>修改日期：2008年7月6日<br>原文参见：<a  href="http://code.google.com/p/googletest/wiki/GoogleTestPrimer">http://code.<span class="hilite1"><span class="hilite1">google</span></span>.com/p/<span class="hilite1"><span class="hilite1">google</span></span><span class="hilite2"><span class="hilite2">test</span></span>/wiki/<span class="hilite1"><span class="hilite1">Google</span></span><span class="hilite2"><span class="hilite2">Test</span></span>Primer</a></p>
<p>译文地址：http://www.javaeye.com/topic/212024
</p>
<p>&nbsp;</p>
<p><strong>Introduction</strong><strong>：为什么需要</strong><strong><span class="hilite1"><span class="hilite1">Google</span></span> C++ </strong><strong>测试框架？</strong>
</p>
<p>&nbsp;</p>
<p><span class="hilite1"><span class="hilite1">Google</span></span> C++ 测试框架帮助你更好地编写C++测试。
</p>
<p>&nbsp;</p>
<p>无论你是在Linux，Windows，还是Mac环境下工作，只要你编写C++代码，<span class="hilite1"><span class="hilite1">Google</span></span> 测试框架都可以帮上忙。
</p>
<p>&nbsp;</p>
<p>那么，哪些因素才能构成一个好的测试？以及，<span class="hilite1"><span class="hilite1">Google</span></span> C++ 测试框架怎样满足这些因素？我们相信：
</p>
<ol>
    <li>测试应该是<em>独立</em>、<em>可重复</em>的。因为其他测试成功或失败而导致我们要对自己的测试进行debug是非常痛苦的。<span class="hilite1"><span class="hilite1">Google</span></span> C++
    测试框架通过将每个测试在不同的对象中运行，使得测试分离开来。当一个测试失败时，<span class="hilite1"><span class="hilite1">Google</span></span> C++ 测试框架允许你独立运行它以进行快速除错。
    </li>
    <li>测试应该能够被很好地<em>组织</em>，并反映被测代码的结构。<span class="hilite1"><span class="hilite1">Google</span></span> C++
    测试框架将测试组织成测试案例，案例中的测试可以共享数据和程序分支。这样一种通用模式能够很容易辨识，使得我们的测试容易维护。当开发人员在项目之间转换，开始在一个新的代码基上开始工作时，这种一致性格外有用。
    </li>
    <li>测试应该是<em>可移植</em>、<em>可重用</em>的。开源社区有很多平台独立的代码，它们的测试也应该是平台独立的。除开一些特殊情况，<span class="hilite1"><span class="hilite1">Google</span></span>
    C++ 测试框架运行在不同的操作系统上、与不同的编译器（gcc、icc、MSVC）搭配，<span class="hilite1"><span class="hilite1">Google</span></span> C++ 测试框架的测试很容易与不同的配置一起工作。
    </li>
    <li>当测试失败时，应该提供尽可能多的、关于问题的<em>信息</em>。<span class="hilite1"><span class="hilite1">Google</span></span> C++
    测试框架在第一个测试失败时不会停下来。相反，它只是将当前测试停止，然后继续接下来的测试。你也可以设置对一些非致命的错误进行报告，并接着进行当前的测试。这样，你就可以在一次&#8220;运行-编辑-编译&#8221;循环中检查到并修复多个bug。
    </li>
    <li>测试框架应该能将测试编写人员从一些环境维护的工作中解放出来，使他们能够集中精力于测试的<em>内容</em>。<span class="hilite1"><span class="hilite1">Google</span></span> C++
    测试框架自动记录下所有定义好的测试，不需要用户通过列举来指明哪些测试需要运行。
    </li>
    <li>测试应该<em>快速</em>。使用<span class="hilite1"><span class="hilite1">Google</span></span> C++
    测试框架，你可以重用多个测试的共享资源，一次性完成设置/解除设置，而不用使一个测试去依赖另一测试。</li>
</ol>
<p>因为<span class="hilite1"><span class="hilite1">Google</span></span> C++
测试框架基于著名的xUnit架构，如果你之前使用过JUnit或PyUnit的话，你将会感觉非常熟悉。如果你没有接触过这些测试框架，它也只会占用你大约10分钟的时间来学习基本概念和上手。所以，让我们开始吧！
</p>
<p>&nbsp;</p>
<p>Note：本文偶尔会用&#8220;<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>&#8221;来代指&#8220;<span class="hilite1"><span class="hilite1">Google</span></span> C++ 测试框架&#8221;。
</p>
<p>&nbsp;</p>
<p><strong>基本概念</strong></p>
<p>&nbsp;</p>
<p>使用<span class="hilite1"><span class="hilite1">Google</span></span>
<span class="hilite2"><span class="hilite2">Test</span></span>时，你是从编写<em>断言</em>开始的，而断言是一些检查条件是否为真的语句。一个断言的结果可能是成功、非致命失败，或者致命失败。如果一个致命失败出现，他会结束当前的函数；否则，程序继续正常运行。
</p>
<p>&nbsp;</p>
<p><em>测试</em>使用断言来验证被测代码的行为。如果一个测试崩溃或是出现一个失败的断言，那么，该测试<em>失败</em>；否则该测试<em>成功</em>。
</p>
<p>&nbsp;</p>
<p>一个测试案例（<span class="hilite2"><span class="hilite2">test</span></span>
case）包含了一个或多个测试。你应该将自己的测试分别归类到测试案例中，以反映被测代码的结构。当测试案例中的多个测试需要共享通用对象和子程序时，你可以把他们放到一个测试固件（<em><span class="hilite2"><span class="hilite2">test</span></span>
fixture</em>）类中。
</p>
<p>&nbsp;</p>
<p>一个<em>测试程序</em>可以包含多个测试案例。
</p>
<p>&nbsp;</p>
<p>从编写单个的断言开始，到创建测试和测试案例，我们将会介绍怎样编写一个测试程序。
</p>
<p>&nbsp;</p>
<p><strong>断言</strong>
</p>
<p>&nbsp;</p>
<p><span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>中的断言是一些与函数调用相似的宏。要测试一个类或函数，我们需要对其行为做出断言。当一个断言失败时，<span class="hilite1"><span class="hilite1">Google</span></span>
<span class="hilite2"><span class="hilite2">Test</span></span>会在屏幕上输出该代码所在的源文件及其所在的位置行号，以及错误信息。也可以在编写断言时，提供一个自定义的错误信息，这个信息在失败时会被附加在<span class="hilite1"><span class="hilite1">Google</span></span>
<span class="hilite2"><span class="hilite2">Test</span></span>的错误信息之后。
</p>
<p>&nbsp;</p>
<p>断言常常成对出现，它们都测试同一个类或者函数，但对当前功能有着不同的效果。ASSERT_*版本的断言失败时会产生致命失败，并<strong>结束当前函数</strong>。EXPECT_*版本的断言产生非致命失败，而不会中止当前函数。通常更推荐使用EXPECT_*断言，因为它们运行一个测试中可以有不止一个的错误被报告出来。但如果在编写断言如果失败，就没有必要继续往下执行的测试时，你应该使用ASSERT_*断言。
</p>
<p>&nbsp;</p>
<p>因为失败的ASSERT_*断言会立刻从当前的函数返回，可能会跳过其后的一些的清洁代码，这样也许会导致空间泄漏。根据泄漏本身的特质，这种情况
也许值得修复，也可能不值得我们关心——所以，如果你得到断言错误的同时，还得到了一个堆检查的错误，记住上面我们所说的这一点。 </p>
<p>&nbsp;</p>
<p>要提供一个自定义的错误消息，只需要使用&lt;&lt;操作符，或一个&lt;&lt;操作符的序列，将其输入到框架定义的宏中。下面是一个例子：
</p>
<p>&nbsp;</p>
&nbsp;
<div class="dp-highlighter">
<ol class="dp-cpp" start="1">
    <li><span><span>ASSERT_EQ(x.size(),&nbsp;y.size())&nbsp;&lt;&lt;&nbsp;</span><span class="string">"Vectors&nbsp;x&nbsp;and&nbsp;y&nbsp;are&nbsp;of&nbsp;unequal&nbsp;length"</span><span>;&nbsp;&nbsp;</span></span></li>
    <li><span><span class="keyword">for</span><span>&nbsp;(</span><span class="datatypes">int</span><span>&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;x.size();&nbsp;++i)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;EXPECT_EQ(x[i],&nbsp;y[i])&nbsp;&lt;&lt;&nbsp;<span class="string">"Vectors&nbsp;x&nbsp;and&nbsp;y&nbsp;differ&nbsp;at&nbsp;index&nbsp;"</span><span>&nbsp;&lt;&lt;&nbsp;i;&nbsp;&nbsp;</span></span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none;" name="code" class="cpp">ASSERT_EQ(x.size(), y.size()) &lt;&lt; "Vectors x and y are of unequal length";
for (int i = 0; i &lt; x.size(); ++i) {
EXPECT_EQ(x[i], y[i]) &lt;&lt; "Vectors x and y differ at index " &lt;&lt; i;
}</pre>
&nbsp;
<p>任何能够被输出到ostream中的信息都可以被输出到一个断言宏中——特别是C字符串和string对象。如果一个宽字符串
（wchar_t*，windows上UNICODE模式TCHAR*或std::wstring）被输出到一个断言中，在打印时它会被转换成UTF-8
编码。 </p>
<p>&nbsp;</p>
<p><strong>基本断言</strong>
</p>
<p>&nbsp;</p>
<p>下面这些断言实现了基本的true/false条件测试。
</p>
<p>&nbsp;</p>
<table border="1" cellpadding="0" cellspacing="0" width="500">
    <tbody>
        <tr>
            <td valign="top" width="167"><strong>致命断言</strong></td>
            <td valign="top" width="166"><strong>非致命断言</strong></td>
            <td valign="top" width="165"><strong>验证条件</strong></td>
        </tr>
        <tr>
            <td valign="top" width="167">ASSERT_TRUE(<em>condition</em>);</td>
            <td valign="top" width="166">EXPECT_TRUE(<em>condition</em>); </td>
            <td valign="top" width="165"><em>condition</em>为真</td>
        </tr>
        <tr>
            <td valign="top" width="167">ASSERT_FALSE(<em>condition</em>); </td>
            <td valign="top" width="166">EXPECT_FALSE(<em>condition</em>); </td>
            <td valign="top" width="165"><em>condition</em> 为假</td>
        </tr>
    </tbody>
</table>
<p>&nbsp;</p>
<p>记住，当它们失败时，ASSERT_*产生一个致命失败并从当前函数返回，而EXCEPT_*产生一个非致命失败，允许函数继续运行。在两种情况下，一个断言失败都意味着它所包含的测试失败。
</p>
<p>&nbsp;</p>
<p>有效平台：Linux、Windows、Mac。
</p>
<p>&nbsp;</p>
<p><strong>二进制比较</strong>
</p>
<p>&nbsp;</p>
<p>本节描述了比较两个值的一些断言。
</p>
<p>&nbsp;</p>
<table border="1" cellpadding="2" cellspacing="0" width="500">
    <tbody>
        <tr>
            <td valign="top" width="166"><strong>致命断言</strong></td>
            <td valign="top" width="166"><strong>非致命断言</strong></td>
            <td valign="top" width="166"><strong>验证条件</strong></td>
        </tr>
        <tr>
            <td valign="top" width="166">ASSERT_EQ(<em>expected</em>, <em>actual</em>);</td>
            <td valign="top" width="166">EXPECT_EQ(<em>expected</em>, <em>actual</em>);</td>
            <td valign="top" width="166"><em>expected</em> == <em>actual</em></td>
        </tr>
        <tr>
            <td valign="top" width="166">ASSERT_NE(<em>val1</em>, <em>val2</em>);</td>
            <td valign="top" width="166">EXPECT_NE(<em>val1</em>, <em>val2</em>);</td>
            <td valign="top" width="166"><em>val1</em> != <em>val2</em></td>
        </tr>
        <tr>
            <td valign="top" width="166">ASSERT_LT(<em>val1</em>, <em>val2</em>);</td>
            <td valign="top" width="166">EXPECT_LT(<em>val1</em>, <em>val2</em>);</td>
            <td valign="top" width="166"><em>val1</em> &lt; <em>val2</em></td>
        </tr>
        <tr>
            <td valign="top" width="166">ASSERT_LE(<em>val1</em>, <em>val2</em>);</td>
            <td valign="top" width="166">EXPECT_LE(<em>val1</em>, <em>val2</em>);</td>
            <td valign="top" width="166"><em>val1</em> &lt;= <em>val2</em></td>
        </tr>
        <tr>
            <td valign="top" width="166">ASSERT_GT(<em>val1</em>, <em>val2</em>);</td>
            <td valign="top" width="166">EXPECT_GT(<em>val1</em>, <em>val2</em>);</td>
            <td valign="top" width="166"><em>val1</em> &gt; <em>val2</em></td>
        </tr>
        <tr>
            <td valign="top" width="166">ASSERT_GE(<em>val1</em>, <em>val2</em>);</td>
            <td valign="top" width="166">EXPECT_GE(<em>val1</em>, <em>val2</em>);</td>
            <td valign="top" width="166"><em>val1</em> &gt;= <em>val2</em></td>
        </tr>
    </tbody>
</table>
<p>&nbsp;</p>
<p>在出现失败事件时，<span class="hilite1"><span class="hilite1">Google</span></span>
<span class="hilite2"><span class="hilite2">Test</span></span>会将两个值（<em>Val1</em>和<em>Val2</em>）都打印出来。在ASSERT_EQ*和EXCEPT_EQ*断言（以及我们随后介绍类似的断言）中，你应该把你希望测试的表达式放在<em>actual</em>（实际值）的位置上，将其期望值放在<em>expected</em>（期望值）的位置上，因为<span class="hilite1"><span class="hilite1">Google</span></span>
<span class="hilite2"><span class="hilite2">Test</span></span>的测试消息为这种惯例做了一些优化。
</p>
<p>&nbsp;</p>
<p>参数值必须是可通过断言的比较操作符进行比较的，否则你会得到一个编译错误。参数值还必须支持&lt;&lt;操作符来将值输入到ostream中。所有的C++内置类型都支持这一点。
</p>
<p>&nbsp;</p>
<p>这些断言可以用于用户自定义的型别，但你必须重载相应的比较操作符（如==、&lt;等）。如果定义有相应的操作符，推荐使用ASSERT_*()宏，因为它们不仅会输出比较的结果，还会输出两个比较对象。
</p>
<p>&nbsp;</p>
<p>参数表达式总是只被解析一次。因此，参数表达式有一定的副作用（side
effect，这里应该是指编译器不同，操作符解析顺序的不确定性）也是可以接受的。但是，同其他普通C/C++函数一样，参数表达式的解析顺序是不确定的（如，一种编译器可以自由选择一种顺序来进行解析），而你的代码不应该依赖于某种特定的参数解析顺序。
</p>
<p>&nbsp;</p>
<p>ASSERT_EQ()对指针进行的是指针比较。即，如果被用在两个C字符串上，它会比较它们是否指向同样的内存地址，而不是它们所指向的字符串是否有相同值。所以，如果你想对两个C字符串（例如，const
char*）进行值比较，请使用ASSERT_STREQ()宏，该宏会在后面介绍到。特别需要一提的是，要验证一个C字符串是否为空（NULL），使用ASSERT_STREQ(NULL,
c_string)。但是要比较两个string对象时，你应该使用ASSERT_EQ。
</p>
<p>&nbsp;</p>
<p>本节中介绍的宏都可以处理窄字符串对象和宽字符串对象（string和wstring）。
</p>
<p>&nbsp;</p>
<p>有效平台：Linux、Windows、Mac。
</p>
<p>&nbsp;</p>
<p><strong>字符串比较</strong></p>
<p>&nbsp;</p>
<p>该组断言用于比较两个C字符串。如果你想要比较两个string对象，相应地使用EXPECT_EQ、EXPECT_NE等断言。
</p>
<p>&nbsp;</p>
<table border="1" cellpadding="2" cellspacing="0" width="700">
    <tbody>
        <tr>
            <td valign="top" width="235"><strong>致命断言</strong></td>
            <td valign="top" width="234"><strong>非致命断言</strong></td>
            <td valign="top" width="229"><strong>验证条件</strong></td>
        </tr>
        <tr>
            <td valign="top" width="235">ASSERT_STREQ(<em>expected_str</em>,
            <em>actual_str</em>);</td>
            <td valign="top" width="234">EXPECT_STREQ(<em>expected_str</em>,
            <em>actual_str</em>);</td>
            <td valign="top" width="229">两个C字符串有相同的内容</td>
        </tr>
        <tr>
            <td valign="top" width="235">ASSERT_STRNE(<em>str1</em>, <em>str2</em>);</td>
            <td valign="top" width="234">EXPECT_STRNE(<em>str1</em>, <em>str2</em>);</td>
            <td valign="top" width="229">两个C字符串有不同的内容</td>
        </tr>
        <tr>
            <td valign="top" width="235">ASSERT_STRCASEEQ(<em>expected_str</em>,
            <em>actual_str</em>);</td>
            <td valign="top" width="234">EXPECT_STRCASEEQ(<em>expected_str</em>,
            <em>actual_str</em>);</td>
            <td valign="top" width="229">两个C字符串有相同的内容，忽略大小写</td>
        </tr>
        <tr>
            <td valign="top" width="235">ASSERT_STRCASENE(<em>str1</em>, <em>str2</em>);</td>
            <td valign="top" width="234">EXPECT_STRCASENE(<em>str1</em>, <em>str2</em>);</td>
            <td valign="top" width="229">两个C字符串有不同的内容，忽略大小写</td>
        </tr>
    </tbody>
</table>
<p>&nbsp;</p>
<p>注意断言名称中出现的&#8220;CASE&#8221;意味着大小写被忽略了。
</p>
<p>&nbsp;</p>
<p>*STREQ*和*STRNE*也接受宽字符串（wchar_t*）。如果两个宽字符串比较失败，它们的值会做为UTF-8窄字符串被输出。
</p>
<p>&nbsp;</p>
<p>一个NULL空指针和一个空字符串会被认为是<em>不一样</em>的。
</p>
<p>&nbsp;</p>
<p>有效平台：Linux、Windows、Mac。
</p>
<p>&nbsp;</p>
<p>参见：更多的字符串比较的技巧（如子字符串、前缀和正则表达式匹配），请参见[Advanced Guide Advanced <span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>
Guide]。
</p>
<p>&nbsp;</p>
<p><strong>简单的测试</strong>
</p>
<p>&nbsp;</p>
<p>要创建一个测试：
</p>
<ol>
    <li>使用<span class="hilite2"><span class="hilite2">TEST</span></span>（）宏来定义和命名一个测试函数，它们是一些没有返回值的普通C++函数。
    </li>
    <li>在这个函数中，与你想要包含的其它任何有效C++代码一起，使用<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>提供的各种断言来进行检查。
    </li>
    <li>测试的结果由其中的断言决定；如果测试中的任意断言失败（无论是致命还是非致命），或者测试崩溃，那么整个测试就失败了。否则，测试通过。&nbsp;
    </li>
</ol>
<div class="dp-highlighter">
<ol class="dp-cpp" start="1">
    <li><span><span><span class="hilite2"><span class="hilite2">TEST</span></span>(<span class="hilite2"><span class="hilite2">test</span></span>_case_name,&nbsp;<span class="hilite2"><span class="hilite2">test</span></span>_name)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li><span>...&nbsp;<span class="hilite2"><span class="hilite2">test</span></span>&nbsp;body&nbsp;...&nbsp;&nbsp;</span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none;" name="code" class="cpp"><span class="hilite2"><span class="hilite2">TEST</span></span>(<span class="hilite2"><span class="hilite2">test</span></span>_case_name, <span class="hilite2"><span class="hilite2">test</span></span>_name) {
... <span class="hilite2"><span class="hilite2">test</span></span> body ...
}</pre>
&nbsp;
<p><span class="hilite2"><span class="hilite2">TEST</span></span>（）的参数是从概括到特殊的。<em>第一个</em>参数是测试案例的名称，<em>第二个</em>参数是测试案例中的测试的名称。记住，一个测试案例可以包含任意数量的独立测试。一个测试的<em>全称</em>包括了包含它的测试案例名称，及其独立的名称。不同测试案例中的独立测试可以有相同的名称。
</p>
<p>&nbsp;</p>
<p>举例来说，让我们看一个简单的整数函数：
</p>
<p>&nbsp;</p>
<div class="dp-highlighter">
<ol class="dp-cpp" start="1">
    <li><span><span class="datatypes">int</span><span>&nbsp;Factorial(</span><span class="datatypes">int</span><span>&nbsp;n);&nbsp;</span><span class="comment">//&nbsp;返回n的阶乘</span><span>&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre style="display: none;" name="code" class="cpp">int Factorial(int n); // 返回n的阶乘</pre>
&nbsp;
<p>&nbsp;</p>
<p><span style="font-family: courier new,courier;">这个函数的测试案例应该看起来像是：
</span></p>
<p>&nbsp;</p>
<div class="dp-highlighter">
<ol class="dp-cpp" start="1">
    <li><span><span class="comment">//&nbsp;测试0的阶乘</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span><span class="hilite2"><span class="hilite2">TEST</span></span>(Factorial<span class="hilite2"><span class="hilite2">Test</span></span>,&nbsp;HandlesZeroInput)&nbsp;{&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;EXPECT_EQ(1,&nbsp;Factorial(0));&nbsp;&nbsp;</span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
    <li><span><span class="comment">//&nbsp;测试正数的阶乘</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span><span class="hilite2"><span class="hilite2">TEST</span></span>(Factorial<span class="hilite2"><span class="hilite2">Test</span></span>,&nbsp;HandlesPositiveInput)&nbsp;{&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;EXPECT_EQ(1,&nbsp;Factorial(1));&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;EXPECT_EQ(2,&nbsp;Factorial(2));&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;EXPECT_EQ(6,&nbsp;Factorial(3));&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;EXPECT_EQ(40320,&nbsp;Factorial(8));&nbsp;&nbsp;</span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none;" name="code" class="cpp">// 测试0的阶乘
<span class="hilite2"><span class="hilite2">TEST</span></span>(Factorial<span class="hilite2"><span class="hilite2">Test</span></span>, HandlesZeroInput) {
EXPECT_EQ(1, Factorial(0));
}
// 测试正数的阶乘
<span class="hilite2"><span class="hilite2">TEST</span></span>(Factorial<span class="hilite2"><span class="hilite2">Test</span></span>, HandlesPositiveInput) {
EXPECT_EQ(1, Factorial(1));
EXPECT_EQ(2, Factorial(2));
EXPECT_EQ(6, Factorial(3));
EXPECT_EQ(40320, Factorial(8));
}</pre>
&nbsp;
<p>&nbsp;</p>
<p><span class="hilite1"><span class="hilite1">Google</span></span>
<span class="hilite2"><span class="hilite2">Test</span></span>根据测试案例来分组收集测试结果，因此，逻辑相关的测试应该在同一测试案例中；换句话说，它们的<span class="hilite2"><span class="hilite2">TEST</span></span>（）的第一个参数应该是一样的。在上面的例子中，我们有两个测试，HandlesZeroInput和HandlesPostiveInput，它们都属于同一个测试案例Factorial<span class="hilite2"><span class="hilite2">Test</span></span>。
</p>
<p>&nbsp;</p>
<p>有效平台：Linux、Windows、Mac。
</p>
<p>&nbsp;</p>
<p><strong>测试固件（</strong><strong><span class="hilite2"><span class="hilite2">Test</span></span> Fixtures</strong><strong>，又做测试夹具、测试套件）：在多个测试中使用同样的数据配置</strong>
</p>
<p>&nbsp;</p>
<p>当你发现自己编写了两个或多个测试来操作同样的数据，你可以采用一个<em>测试固件</em>。它让你可以在多个不同的测试中重用同样的对象配置。
</p>
<p>&nbsp;</p>
<p>要创建测试固件，只需：
</p>
<ol>
    <li>创建一个类继承自<span class="hilite2"><span class="hilite2">test</span></span>ing::<span class="hilite2"><span class="hilite2">Test</span></span>。将其中的成员声明为protected:或是public:，因为我们想要从子类中存取固件成员。
    </li>
    <li>在该类中声明你计划使用的任何对象。
    </li>
    <li>如果需要，编写一个默认构造函数或者SetUp()函数来为每个测试准备对象。常见错误包括将SetUp()拼写为Setup()（小写了u）——不要让它发生在你身上。
    </li>
    <li>如果需要，编写一个析构函数或者TearDown()函数来释放你在SetUp()函数中申请的资源。要知道什么时候应该使用构造函数/析构函数，什么时候又应该使用SetUp()/TearDown()函数，阅读我们的FAQ。
    </li>
    <li>如果需要，定义你的测试所需要共享的子程序。</li>
</ol>
<p>当我们要使用固件时，使用<span class="hilite2"><span class="hilite2">TEST</span></span>_F()替换掉<span class="hilite2"><span class="hilite2">TEST</span></span>()，它允许我们存取测试固件中的对象和子程序：
</p>
<p>&nbsp;</p>
<div class="dp-highlighter">
<ol class="dp-cpp" start="1">
    <li><span><span><span class="hilite2"><span class="hilite2">TEST</span></span>_F(<span class="hilite2"><span class="hilite2">test</span></span>_case_name,&nbsp;<span class="hilite2"><span class="hilite2">test</span></span>_name)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li><span>...&nbsp;<span class="hilite2"><span class="hilite2">test</span></span>&nbsp;body&nbsp;...&nbsp;&nbsp;</span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none;" name="code" class="cpp"><span class="hilite2"><span class="hilite2">TEST</span></span>_F(<span class="hilite2"><span class="hilite2">test</span></span>_case_name, <span class="hilite2"><span class="hilite2">test</span></span>_name) {
... <span class="hilite2"><span class="hilite2">test</span></span> body ...
}</pre>
<p>&nbsp;</p>
<p>与<span class="hilite2"><span class="hilite2">TEST</span></span>()一样，第一个参数是测试案例的名称，但对<span class="hilite2"><span class="hilite2">TEST</span></span>_F()来说，这个名称必须与测试固件类的名称一些。你可能已经猜到了：_F正是指固件。
</p>
<p>&nbsp;</p>
<p>不幸地是，C++宏系统并不允许我们创建一个单独的宏来处理两种类型的测试。使用错误的宏会导致编译期的错误。
</p>
<p>&nbsp;</p>
<p>而且，你必须在<span class="hilite2"><span class="hilite2">TEST</span></span>_F()中使用它之前，定义好这个测试固件类。否则，你会得到编译器的报错：&#8220;virtual outside class
declaration&#8221;。
</p>
<p>对于<span class="hilite2"><span class="hilite2">TEST</span></span>_F()中定义的每个测试，<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>将会：
</p>
<ol>
    <li>在运行时创建一个<em>全新</em>的测试固件
    </li>
    <li>马上通过SetUp()初始化它，
    </li>
    <li>运行测试
    </li>
    <li>调用TearDown()来进行清理工作
    </li>
    <li>删除测试固件。注意，同一测试案例中，不同的测试拥有不同的测试固件。<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>在创建下一个测试固件前总是会对现有固件进行删除。<span class="hilite1"><span class="hilite1">Google</span></span>
    <span class="hilite2"><span class="hilite2">Test</span></span>不会对多个测试重用一个测试固件。测试对测试固件的改动并不会影响到其他测试。</li>
</ol>
<p>例如，让我们为一个名为Queue的FIFO队列类编写测试，该类的接口如下：
</p>
&nbsp;
<div class="dp-highlighter">
<ol class="dp-cpp" start="1">
    <li><span><span class="keyword">template</span><span>&nbsp;&lt;</span><span class="keyword">typename</span><span>&nbsp;E&gt;&nbsp;</span><span class="comment">//&nbsp;E为元素类型</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span><span class="keyword">class</span><span>&nbsp;Queue&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li><span><span class="keyword">public</span><span>:&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;Queue();&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;<span class="keyword">void</span><span>&nbsp;Enqueue(</span><span class="keyword">const</span><span>&nbsp;E&amp;&nbsp;element);&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;E*&nbsp;Dequeue();&nbsp;<span class="comment">//&nbsp;返回&nbsp;NULL&nbsp;如果队列为空.</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;<span class="datatypes">size_t</span><span>&nbsp;size()&nbsp;</span><span class="keyword">const</span><span>;&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;...&nbsp;&nbsp;</span></li>
    <li><span>};&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none;" name="code" class="cpp">template &lt;typename E&gt; // E为元素类型
class Queue {
public:
Queue();
void Enqueue(const E&amp; element);
E* Dequeue(); // 返回 NULL 如果队列为空.
size_t size() const;
...
};</pre>
<p>&nbsp;</p>
<p>首先，定义一个固件类。习惯上，你应该把它的名字定义为Foo<span class="hilite2"><span class="hilite2">Test</span></span>，这里的Foo是被测试的类。
</p>
&nbsp;
<div class="dp-highlighter">
<ol class="dp-cpp" start="1">
    <li><span><span class="keyword">class</span><span>&nbsp;Queue<span class="hilite2"><span class="hilite2">Test</span></span>&nbsp;:&nbsp;</span><span class="keyword">public</span><span>&nbsp;<span class="hilite2"><span class="hilite2">test</span></span>ing::<span class="hilite2"><span class="hilite2">Test</span></span>&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li><span><span class="keyword">protected</span><span>:&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;<span class="keyword">virtual</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;SetUp()&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;q1_.Enqueue(1);&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;q2_.Enqueue(2);&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;q2_.Enqueue(3);&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;<span class="comment">//&nbsp;virtual&nbsp;void&nbsp;TearDown()&nbsp;{}</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;Queue&lt;<span class="datatypes">int</span><span>&gt;&nbsp;q0_;&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;Queue&lt;<span class="datatypes">int</span><span>&gt;&nbsp;q1_;&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;Queue&lt;<span class="datatypes">int</span><span>&gt;&nbsp;q2_;&nbsp;&nbsp;</span></span></li>
    <li><span>};&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none;" name="code" class="cpp">class Queue<span class="hilite2"><span class="hilite2">Test</span></span> : public <span class="hilite2"><span class="hilite2">test</span></span>ing::<span class="hilite2"><span class="hilite2">Test</span></span> {
protected:
virtual void SetUp() {
q1_.Enqueue(1);
q2_.Enqueue(2);
q2_.Enqueue(3);
}
// virtual void TearDown() {}
Queue&lt;int&gt; q0_;
Queue&lt;int&gt; q1_;
Queue&lt;int&gt; q2_;
};</pre>
&nbsp;
<p>在这个案例中，我们不需要TearDown()，因为每个测试后除了析构函数外不需要进行其它的清理工作了。
</p>
<p>&nbsp;</p>
<p>接下来我们使用<span class="hilite2"><span class="hilite2">TEST</span></span>_F()和这个固件来编写测试。
</p>
<p>&nbsp;</p>
<div class="dp-highlighter">
<ol class="dp-cpp" start="1">
    <li><span><span><span class="hilite2"><span class="hilite2">TEST</span></span>_F(Queue<span class="hilite2"><span class="hilite2">Test</span></span>,&nbsp;IsEmptyInitially)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;EXPECT_EQ(0,&nbsp;q0_.size());&nbsp;&nbsp;</span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
    <li><span><span class="hilite2"><span class="hilite2">TEST</span></span>_F(Queue<span class="hilite2"><span class="hilite2">Test</span></span>,&nbsp;DequeueWorks)&nbsp;{&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;<span class="datatypes">int</span><span>*&nbsp;n&nbsp;=&nbsp;q0_.Dequeue();&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;EXPECT_EQ(NULL,&nbsp;n);&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;n&nbsp;=&nbsp;q1_.Dequeue();&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;ASSERT_TRUE(n&nbsp;!=&nbsp;NULL);&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;EXPECT_EQ(1,&nbsp;*n);&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;EXPECT_EQ(0,&nbsp;q1_.size());&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;<span class="keyword">delete</span><span>&nbsp;n;&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;n&nbsp;=&nbsp;q2_.Dequeue();&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;ASSERT_TRUE(n&nbsp;!=&nbsp;NULL);&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;EXPECT_EQ(2,&nbsp;*n);&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;EXPECT_EQ(1,&nbsp;q2_.size());&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;<span class="keyword">delete</span><span>&nbsp;n;&nbsp;&nbsp;</span></span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none;" name="code" class="cpp"><span class="hilite2"><span class="hilite2">TEST</span></span>_F(Queue<span class="hilite2"><span class="hilite2">Test</span></span>, IsEmptyInitially) {
EXPECT_EQ(0, q0_.size());
}
<span class="hilite2"><span class="hilite2">TEST</span></span>_F(Queue<span class="hilite2"><span class="hilite2">Test</span></span>, DequeueWorks) {
int* n = q0_.Dequeue();
EXPECT_EQ(NULL, n);
n = q1_.Dequeue();
ASSERT_TRUE(n != NULL);
EXPECT_EQ(1, *n);
EXPECT_EQ(0, q1_.size());
delete n;
n = q2_.Dequeue();
ASSERT_TRUE(n != NULL);
EXPECT_EQ(2, *n);
EXPECT_EQ(1, q2_.size());
delete n;
}</pre>
&nbsp;
<p>上面这段代码既使用了ASSERT_*断言，又使用了EXPECT_*断言。经验上讲，如果你想要断言失败后，测试能够继续进行以显示更多的错误
时，你应该使用EXPECT_*断言；使用ASSERT_*如果该断言失败后继续往下执行毫无意义。例如，Dequeue测试中的第二个断言是
ASSERT_TURE(n!= NULL)，因为我们随后会n指针解引用，如果n指针为空的话，会导致一个段错误。 </p>
<p>&nbsp;</p>
<p>当这些测试开始时，会发生如下情况：
</p>
<ol>
    <li><span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>创建一个Queue<span class="hilite2"><span class="hilite2">Test</span></span>对象（我们把它叫做t1）。
    </li>
    <li>t1.SetUp()初始化t1。
    </li>
    <li>第一个测试（IsEmptyInitiallly）在t1上运行。
    </li>
    <li>测试完成后，t1.TearDown()进行一些清理工作。
    </li>
    <li>t1被析构。
    </li>
    <li>以上步骤在另一个Queue<span class="hilite2"><span class="hilite2">Test</span></span>对象上重复进行，这回会运行DequeueWorks测试。</li>
</ol>
<p>有效平台：Linux、Windows、Mac。
</p>
<p>&nbsp;</p>
<p>注意：当一个测试对象被构造时，<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>会自动地保存所有的<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>变量标识，对象析构后进行恢复。
</p>
<p>&nbsp;</p>
<p><strong>调用测试</strong>
</p>
<p>&nbsp;</p>
<p><span class="hilite2"><span class="hilite2">TEST</span></span>()和<span class="hilite2"><span class="hilite2">TEST</span></span>_F()向<span class="hilite1"><span class="hilite1">Google</span></span>
<span class="hilite2"><span class="hilite2">Test</span></span>隐式注册它们的测试。因此，与很多其他的C++测试框架不同，你不需要为了运行你定义的测试而将它们全部再列出来一次。
</p>
<p>&nbsp;</p>
<p>在定义好测试后，你可以通过RUN_ALL_<span class="hilite2"><span class="hilite2">TEST</span></span>S()来运行它们，如果所有测试成功，该函数返回0，否则会返回1.注意RUN_ALL_<span class="hilite2"><span class="hilite2">TEST</span></span>S()会运行你链接到的所有测试——它们可以来自不同的测试案例，甚至是来自不同的文件。
</p>
<p>&nbsp;</p>
<p>当被调用时，RUN_ALL_<span class="hilite2"><span class="hilite2">TEST</span></span>S()宏会：
</p>
<ol>
    <li>保存所有的<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>标志。
    </li>
    <li>为一个侧测试创建测试固件对象。
    </li>
    <li>调用SetUp()初始化它。
    </li>
    <li>在固件对象上运行测试。
    </li>
    <li>调用TearDown()清理固件。
    </li>
    <li>删除固件。
    </li>
    <li>恢复所有<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>标志的状态。
    </li>
    <li>重复上诉步骤，直到所有测试完成。</li>
</ol>
<p>此外，如果第二步时，测试固件的构造函数产生一个致命错误，继续执行3至5部显然没有必要，所以它们会被跳过。与之相似，如果第3部产生致命错误，第4部也会被跳过。
</p>
<p>&nbsp;</p>
<p>重要：你不能忽略掉RUN_ALL_<span class="hilite2"><span class="hilite2">TEST</span></span>S()的返回值，否则gcc会报一个编译错误。这样设计的理由是自动化测试服务会根据测试退出返回码来决定一个测试是否通过，而不是根据其stdout/stderr输出；因此你的main()函数必须返回RUN_ALL_<span class="hilite2"><span class="hilite2">TEST</span></span>S()的值。
</p>
<p>&nbsp;</p>
<p>而且，你应该只调用RUN_ALL_<span class="hilite2"><span class="hilite2">TEST</span></span>S()一次。多次调用该函数会与<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>的一些高阶特性（如线程安全死亡测试thread-safe
death <span class="hilite2"><span class="hilite2">test</span></span>s）冲突，因而是不被支持的。
</p>
<p>&nbsp;</p>
<p>有效平台：Linux、Windows、Mac。
</p>
<p>&nbsp;</p>
<p><strong>编写</strong><strong>main()</strong><strong>函数</strong>
</p>
<p>&nbsp;</p>
<p>你可以从下面这个样板开始:
</p>
<p>&nbsp;</p>
<div class="dp-highlighter">
<ol class="dp-cpp" start="1">
    <li><span><span class="preprocessor">#include&nbsp;"this/package/foo.h"</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span><span class="preprocessor">#include&nbsp;&lt;g<span class="hilite2"><span class="hilite2">test</span></span>/g<span class="hilite2"><span class="hilite2">test</span></span>.h&gt;</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span><span class="keyword">namespace</span><span>&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li><span><span class="comment">//&nbsp;测试Foo类的测试固件</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span><span class="keyword">class</span><span>&nbsp;Foo<span class="hilite2"><span class="hilite2">Test</span></span>&nbsp;:&nbsp;</span><span class="keyword">public</span><span>&nbsp;<span class="hilite2"><span class="hilite2">test</span></span>ing::<span class="hilite2"><span class="hilite2">Test</span></span>&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li><span><span class="keyword">protected</span><span>:&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;<span class="comment">//&nbsp;You&nbsp;can&nbsp;remove&nbsp;any&nbsp;or&nbsp;all&nbsp;of&nbsp;the&nbsp;following&nbsp;functions&nbsp;if&nbsp;its&nbsp;body</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;<span class="comment">//&nbsp;is&nbsp;empty.</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;Foo<span class="hilite2"><span class="hilite2">Test</span></span>()&nbsp;{&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;You&nbsp;can&nbsp;do&nbsp;set-up&nbsp;work&nbsp;for&nbsp;each&nbsp;<span class="hilite2"><span class="hilite2">test</span></span>&nbsp;here.</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;<span class="keyword">virtual</span><span>&nbsp;~Foo<span class="hilite2"><span class="hilite2">Test</span></span>()&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;You&nbsp;can&nbsp;do&nbsp;clean-up&nbsp;work&nbsp;that&nbsp;doesn't&nbsp;throw&nbsp;exceptions&nbsp;here.</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;<span class="comment">//&nbsp;If&nbsp;the&nbsp;constructor&nbsp;and&nbsp;destructor&nbsp;are&nbsp;not&nbsp;enough&nbsp;for&nbsp;setting&nbsp;up</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;<span class="comment">//&nbsp;and&nbsp;cleaning&nbsp;up&nbsp;each&nbsp;<span class="hilite2"><span class="hilite2">test</span></span>,&nbsp;you&nbsp;can&nbsp;define&nbsp;the&nbsp;following&nbsp;methods:</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;<span class="keyword">virtual</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;SetUp()&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;Code&nbsp;here&nbsp;will&nbsp;be&nbsp;called&nbsp;immediately&nbsp;after&nbsp;the&nbsp;constructor&nbsp;(right</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;before&nbsp;each&nbsp;<span class="hilite2"><span class="hilite2">test</span></span>).</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;<span class="keyword">virtual</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;TearDown()&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;Code&nbsp;here&nbsp;will&nbsp;be&nbsp;called&nbsp;immediately&nbsp;after&nbsp;each&nbsp;<span class="hilite2"><span class="hilite2">test</span></span>&nbsp;(right</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;before&nbsp;the&nbsp;destructor).</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;<span class="comment">//&nbsp;Objects&nbsp;declared&nbsp;here&nbsp;can&nbsp;be&nbsp;used&nbsp;by&nbsp;all&nbsp;<span class="hilite2"><span class="hilite2">test</span></span>s&nbsp;in&nbsp;the&nbsp;<span class="hilite2"><span class="hilite2">test</span></span>&nbsp;case&nbsp;for&nbsp;Foo.</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>};&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span><span class="comment">//&nbsp;<span class="hilite2"><span class="hilite2">Test</span></span>s&nbsp;that&nbsp;the&nbsp;Foo::Bar()&nbsp;method&nbsp;does&nbsp;Abc.</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span><span class="hilite2"><span class="hilite2">TEST</span></span>_F(Foo<span class="hilite2"><span class="hilite2">Test</span></span>,&nbsp;MethodBarDoesAbc)&nbsp;{&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;<span class="keyword">const</span><span>&nbsp;string&nbsp;input_filepath&nbsp;=&nbsp;</span><span class="string">"this/package/<span class="hilite2"><span class="hilite2">test</span></span>data/myinputfile.dat"</span><span>;&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;<span class="keyword">const</span><span>&nbsp;string&nbsp;output_filepath&nbsp;=&nbsp;</span><span class="string">"this/package/<span class="hilite2"><span class="hilite2">test</span></span>data/myoutputfile.dat"</span><span>;&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;Foo&nbsp;f;&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;EXPECT_EQ(0,&nbsp;f.Bar(input_filepath,&nbsp;output_filepath));&nbsp;&nbsp;</span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span><span class="comment">//&nbsp;<span class="hilite2"><span class="hilite2">Test</span></span>s&nbsp;that&nbsp;Foo&nbsp;does&nbsp;Xyz.</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span><span class="hilite2"><span class="hilite2">TEST</span></span>_F(Foo<span class="hilite2"><span class="hilite2">Test</span></span>,&nbsp;DoesXyz)&nbsp;{&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;<span class="comment">//&nbsp;Exercises&nbsp;the&nbsp;Xyz&nbsp;feature&nbsp;of&nbsp;Foo.</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
    <li><span>}&nbsp;&nbsp;<span class="comment">//&nbsp;namespace</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span><span class="datatypes">int</span><span>&nbsp;main(</span><span class="datatypes">int</span><span>&nbsp;argc,&nbsp;</span><span class="datatypes">char</span><span>&nbsp;**argv)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;<span class="hilite2"><span class="hilite2">test</span></span>ing::Init<span class="hilite1"><span class="hilite1">Google</span></span><span class="hilite2"><span class="hilite2">Test</span></span>(&amp;argc,&nbsp;argv);&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;RUN_ALL_<span class="hilite2"><span class="hilite2">TEST</span></span>S();&nbsp;&nbsp;</span></span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none;" name="code" class="cpp">#include "this/package/foo.h"
#include &lt;g<span class="hilite2"><span class="hilite2">test</span></span>/g<span class="hilite2"><span class="hilite2">test</span></span>.h&gt;
namespace {
// 测试Foo类的测试固件
class Foo<span class="hilite2"><span class="hilite2">Test</span></span> : public <span class="hilite2"><span class="hilite2">test</span></span>ing::<span class="hilite2"><span class="hilite2">Test</span></span> {
protected:
// You can remove any or all of the following functions if its body
// is empty.
Foo<span class="hilite2"><span class="hilite2">Test</span></span>() {
// You can do set-up work for each <span class="hilite2"><span class="hilite2">test</span></span> here.
}
virtual ~Foo<span class="hilite2"><span class="hilite2">Test</span></span>() {
// You can do clean-up work that doesn't throw exceptions here.
}
// If the constructor and destructor are not enough for setting up
// and cleaning up each <span class="hilite2"><span class="hilite2">test</span></span>, you can define the following methods:
virtual void SetUp() {
// Code here will be called immediately after the constructor (right
// before each <span class="hilite2"><span class="hilite2">test</span></span>).
}
virtual void TearDown() {
// Code here will be called immediately after each <span class="hilite2"><span class="hilite2">test</span></span> (right
// before the destructor).
}
// Objects declared here can be used by all <span class="hilite2"><span class="hilite2">test</span></span>s in the <span class="hilite2"><span class="hilite2">test</span></span> case for Foo.
};
// <span class="hilite2"><span class="hilite2">Test</span></span>s that the Foo::Bar() method does Abc.
<span class="hilite2"><span class="hilite2">TEST</span></span>_F(Foo<span class="hilite2"><span class="hilite2">Test</span></span>, MethodBarDoesAbc) {
const string input_filepath = "this/package/<span class="hilite2"><span class="hilite2">test</span></span>data/myinputfile.dat";
const string output_filepath = "this/package/<span class="hilite2"><span class="hilite2">test</span></span>data/myoutputfile.dat";
Foo f;
EXPECT_EQ(0, f.Bar(input_filepath, output_filepath));
}
// <span class="hilite2"><span class="hilite2">Test</span></span>s that Foo does Xyz.
<span class="hilite2"><span class="hilite2">TEST</span></span>_F(Foo<span class="hilite2"><span class="hilite2">Test</span></span>, DoesXyz) {
// Exercises the Xyz feature of Foo.
}
}  // namespace
int main(int argc, char **argv) {
<span class="hilite2"><span class="hilite2">test</span></span>ing::Init<span class="hilite1"><span class="hilite1">Google</span></span><span class="hilite2"><span class="hilite2">Test</span></span>(&amp;argc, argv);
return RUN_ALL_<span class="hilite2"><span class="hilite2">TEST</span></span>S();
}</pre>
<p>&nbsp;</p>
<p><span class="hilite2"><span class="hilite2">test</span></span>ing::Init<span class="hilite1"><span class="hilite1">Google</span></span><span class="hilite2"><span class="hilite2">Test</span></span>()函数负责解析命令行传入的<span class="hilite1"><span class="hilite1">Google</span></span>
<span class="hilite2"><span class="hilite2">Test</span></span>标志，并删除所有它可以处理的标志。这使得用户可以通过各种不同的标志控制一个测试程序的行为。关于这一点我们会在G<span class="hilite2"><span class="hilite2">Test</span></span>Advanced中讲到。你必须在调用RUN_ALL_<span class="hilite2"><span class="hilite2">TEST</span></span>S()之前调用该函数，否则就无法正确地初始化标示。
</p>
<p>&nbsp;</p>
<p>在Windows上Init<span class="hilite1"><span class="hilite1">Google</span></span><span class="hilite2"><span class="hilite2">Test</span></span>()可以支持宽字符串，所以它也可以被用在以UNICODE模式编译的程序中。
</p>
<p>&nbsp;</p>
<p><strong>进阶阅读</strong>
</p>
<p>&nbsp;</p>
<p>恭喜你！你已经学到了一些<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>基础。你可以从编写和运行几个<span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>测试开始，再阅读一下<a  href="http://code.google.com/p/googletest/wiki/GoogleTestSamples"><span class="hilite1"><span class="hilite1">Google</span></span><span class="hilite2"><span class="hilite2">Test</span></span>Samples</a>，或是继续研究<a  href="http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide"><span class="hilite1"><span class="hilite1">Google</span></span><span class="hilite2"><span class="hilite2">Test</span></span>AdvancedGuide</a>，其中描述了很多更有用的<span class="hilite1"><span class="hilite1">Google</span></span>
<span class="hilite2"><span class="hilite2">Test</span></span>特性。
</p>
<p>&nbsp;</p>
<p><strong>已知局限</strong>
</p>
<p>&nbsp;</p>
<p><span class="hilite1"><span class="hilite1">Google</span></span> <span class="hilite2"><span class="hilite2">Test</span></span>被设计为线程安全的。但是，我们还没有时间在各种平台上实现同步原语（synchronization
primitives）。因此，目前从两个线程同时使用<span class="hilite1"><span class="hilite1">Google</span></span>
<span class="hilite2"><span class="hilite2">Test</span></span>断言是不安全的。由于通常断言是在主线程中完成的，因此在大多数测试中这都不算问题。如果你愿意帮忙，你可以试着在g<span class="hilite2"><span class="hilite2">test</span></span>-port.h中实现必要的同步原语。</p>
</div><img src ="http://www.cppblog.com/eXile/aggbug/56738.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eXile/" target="_blank">eXile</a> 2008-07-21 11:35 <a href="http://www.cppblog.com/eXile/archive/2008/07/21/56738.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++代码风格谷歌版</title><link>http://www.cppblog.com/eXile/archive/2008/07/01/55046.html</link><dc:creator>eXile</dc:creator><author>eXile</author><pubDate>Tue, 01 Jul 2008 07:24:00 GMT</pubDate><guid>http://www.cppblog.com/eXile/archive/2008/07/01/55046.html</guid><wfw:comment>http://www.cppblog.com/eXile/comments/55046.html</wfw:comment><comments>http://www.cppblog.com/eXile/archive/2008/07/01/55046.html#Feedback</comments><slash:comments>8</slash:comments><wfw:commentRss>http://www.cppblog.com/eXile/comments/commentRss/55046.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/eXile/services/trackbacks/55046.html</trackback:ping><description><![CDATA[&nbsp;&nbsp; 原文地址：&nbsp;<a title="谷歌c++代码风格原文地址" href="http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml?showone=Displaying_Hidden_Details_in_this_Guide#Naming">http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml?showone=Displaying_Hidden_Details_in_this_Guide#Naming</a><br><br>&nbsp;&nbsp; 谷歌的C++代码风格与网上广为流传的林锐风格有很大不同，不过正如文中所言：重要的是保持一致。它还说出了每一种风格的优缺点，这里只说几个比较有意思的。<br>&nbsp;&nbsp; <br>&nbsp;&nbsp; 1）关于空行：<br>&nbsp;&nbsp; 基本原则：使一个屏幕能容纳更多的代码（显然，这是K&amp;R风格的拥趸)<br>&nbsp; <br>&nbsp;&nbsp; 2) 关于引用参数：<br>&nbsp;&nbsp; 所有的引用前加 const, 如下列：<br>&nbsp;&nbsp; void f(const Object&amp; in, Object&amp; out);&nbsp; // bad<br>&nbsp;&nbsp; void f(const Object&amp; in, Object* out);&nbsp; // good<br><br>&nbsp;&nbsp; 以上两点倒是和Qt相似，还有一个相似的地方是：尽量不要用 unsigned。<br><br>&nbsp;&nbsp; 3）关于全局变量：<br>&nbsp;&nbsp; 禁止使用类全局变量，可以使用一些内置类型的全局变量。（为了避免初始化顺序问题）。<br><br>&nbsp;&nbsp; 4）不提倡的C++特性：<br>&nbsp;&nbsp; 尽量不要使用多重继承；<br>
&nbsp;&nbsp; 尽量不要使用操作符重载；<br>
&nbsp;&nbsp; 尽量不要使用函数重载；<br>
&nbsp;&nbsp; 不要使用函数缺省参数；<br>
&nbsp;&nbsp; 不要使用异常；<br>
&nbsp;&nbsp; 不要使用RTTI；<br>&nbsp;&nbsp; 内置的整性类型只使用int.(64位可使用int64_t, 指针兼容可使用intptr_t或ptrdiff_t).<br><br>&nbsp;&nbsp; 具体的理由和更多的风格参见原文。<br>&nbsp;&nbsp; 另外，还可以和Java风格做个对比：<br>&nbsp;&nbsp; <a href_cetemp="http://www.cppblog.com/eXile/admin/EditPosts.aspx" href="">http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html</a><br><br>      <img src ="http://www.cppblog.com/eXile/aggbug/55046.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eXile/" target="_blank">eXile</a> 2008-07-01 15:24 <a href="http://www.cppblog.com/eXile/archive/2008/07/01/55046.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用boost::asio实现一个简单的服务器框架</title><link>http://www.cppblog.com/eXile/archive/2008/05/28/51430.html</link><dc:creator>eXile</dc:creator><author>eXile</author><pubDate>Wed, 28 May 2008 13:00:00 GMT</pubDate><guid>http://www.cppblog.com/eXile/archive/2008/05/28/51430.html</guid><wfw:comment>http://www.cppblog.com/eXile/comments/51430.html</wfw:comment><comments>http://www.cppblog.com/eXile/archive/2008/05/28/51430.html#Feedback</comments><slash:comments>11</slash:comments><wfw:commentRss>http://www.cppblog.com/eXile/comments/commentRss/51430.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/eXile/services/trackbacks/51430.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 利用boost::asio实现一个简单的服务器框架&nbsp;&nbsp;<a href='http://www.cppblog.com/eXile/archive/2008/05/28/51430.html'>阅读全文</a><img src ="http://www.cppblog.com/eXile/aggbug/51430.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eXile/" target="_blank">eXile</a> 2008-05-28 21:00 <a href="http://www.cppblog.com/eXile/archive/2008/05/28/51430.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>boost::asio示例HTTP Server类图</title><link>http://www.cppblog.com/eXile/archive/2008/05/07/49072.html</link><dc:creator>eXile</dc:creator><author>eXile</author><pubDate>Tue, 06 May 2008 16:50:00 GMT</pubDate><guid>http://www.cppblog.com/eXile/archive/2008/05/07/49072.html</guid><wfw:comment>http://www.cppblog.com/eXile/comments/49072.html</wfw:comment><comments>http://www.cppblog.com/eXile/archive/2008/05/07/49072.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/eXile/comments/commentRss/49072.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/eXile/services/trackbacks/49072.html</trackback:ping><description><![CDATA[<p><a href="http://www.cppblog.com/images/cppblog_com/exile/asio_http_1.jpg"><img height=652 alt="" src="http://www.cppblog.com/images/cppblog_com/exile/asio_http_1.jpg" width=878 align=left border=0></a><a href="http://www.cppblog.com/images/cppblog_com/exile/asio_http_1.jpg"></a></p>
<img src ="http://www.cppblog.com/eXile/aggbug/49072.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eXile/" target="_blank">eXile</a> 2008-05-07 00:50 <a href="http://www.cppblog.com/eXile/archive/2008/05/07/49072.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>两个小巧的开源解析库</title><link>http://www.cppblog.com/eXile/archive/2008/04/16/47219.html</link><dc:creator>eXile</dc:creator><author>eXile</author><pubDate>Wed, 16 Apr 2008 05:49:00 GMT</pubDate><guid>http://www.cppblog.com/eXile/archive/2008/04/16/47219.html</guid><wfw:comment>http://www.cppblog.com/eXile/comments/47219.html</wfw:comment><comments>http://www.cppblog.com/eXile/archive/2008/04/16/47219.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/eXile/comments/commentRss/47219.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/eXile/services/trackbacks/47219.html</trackback:ping><description><![CDATA[&nbsp;　这两个库都是Ｃ语言实现的轻量级开源库，具有简单易用和快速高效的特点。<br><br>　１）Expat：ＸＭＬ解析库　<a href="http://expat.sourceforge.net/"><u><font color=#810081>http://expat.sourceforge.net/</font></u></a><br>　　　基于ＳＡＸ事件模型，据说是应用最广泛的ＸＭＬ解析器，为众多的开源软件所采用。注意如果要支持中文，必须使用ＵＴＦ－８编码。<br><br>　２）<span class=ArticleTopTitle id=ctl00_ArticleTopHeader_ArticleTitle>Henry Spencer's Regexp Engine </span>：正则表达式解析库　<a href="http://www.codeproject.com/KB/string/spencerregexp.aspx">http://www.codeproject.com/KB/string/spencerregexp.aspx</a><br>　　　最初由<span class=ArticleTopTitle id=ctl00_ArticleTopHeader_ArticleTitle>Henry Spencer 为tcl/tk所做的正则式实现</span>。由于它的小巧，也被一些其它的开源库所使用。据我所知，MY SQL 数据库，wxWidgets库都采用了这个实现进行正则式分析。为了保持它的简单性，作者也舍弃了一些特征，比如说 {n, m}语法，以及后向引用等。 
<img src ="http://www.cppblog.com/eXile/aggbug/47219.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eXile/" target="_blank">eXile</a> 2008-04-16 13:49 <a href="http://www.cppblog.com/eXile/archive/2008/04/16/47219.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>utf8编码转换</title><link>http://www.cppblog.com/eXile/archive/2008/04/16/47171.html</link><dc:creator>eXile</dc:creator><author>eXile</author><pubDate>Tue, 15 Apr 2008 17:26:00 GMT</pubDate><guid>http://www.cppblog.com/eXile/archive/2008/04/16/47171.html</guid><wfw:comment>http://www.cppblog.com/eXile/comments/47171.html</wfw:comment><comments>http://www.cppblog.com/eXile/archive/2008/04/16/47171.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/eXile/comments/commentRss/47171.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/eXile/services/trackbacks/47171.html</trackback:ping><description><![CDATA[<br>&nbsp;&nbsp;&nbsp;&nbsp; 只用于 Windows 平台.<br><br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">using&nbsp;std::</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>using&nbsp;std::vector;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>inline&nbsp;</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;utf8_trans_impl(</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;from,&nbsp;int&nbsp;from_code,&nbsp;int&nbsp;to_code)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;len16&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;MultiByteToWideChar(from_code,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;from.begin(),&nbsp;from.size(),&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(len16&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vector</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">wchar_t</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;ucs2_buf(len16,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;len16&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;MultiByteToWideChar(from_code,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;from.begin(),&nbsp;from.size(),&nbsp;ucs2_buf.begin(),&nbsp;len16);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;len8&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;WideCharToMultiByte(to_code,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;ucs2_buf,&nbsp;len16,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;result(len8,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WideCharToMultiByte(to_code,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;ucs2_buf.begin(),&nbsp;len16,&nbsp;result.begin(),&nbsp;&nbsp;len8,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;result;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;&nbsp;</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>inline&nbsp;string&nbsp; from_utf8(</span><span style="COLOR: #000000">string&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;from)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>{&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;utf8_trans_impl(&nbsp;from,&nbsp;CP_UTF8,&nbsp;CP_ACP);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>inline&nbsp;string&nbsp; to_utf8(</span><span style="COLOR: #000000">string&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;from)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>{&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;utf8_trans_impl(from,&nbsp;CP_ACP,&nbsp;CP_UTF8);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<br><br>&nbsp;&nbsp;&nbsp;&nbsp; 转载请表明原文地址:&nbsp; <a href="http://www.cppblog.com/exile/"><u><font color=#0000ff>http://www.cppblog.com/exile/</font></u><br></a>
<img src ="http://www.cppblog.com/eXile/aggbug/47171.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eXile/" target="_blank">eXile</a> 2008-04-16 01:26 <a href="http://www.cppblog.com/eXile/archive/2008/04/16/47171.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>GCC4.3...</title><link>http://www.cppblog.com/eXile/archive/2008/03/13/44355.html</link><dc:creator>eXile</dc:creator><author>eXile</author><pubDate>Thu, 13 Mar 2008 03:56:00 GMT</pubDate><guid>http://www.cppblog.com/eXile/archive/2008/03/13/44355.html</guid><wfw:comment>http://www.cppblog.com/eXile/comments/44355.html</wfw:comment><comments>http://www.cppblog.com/eXile/archive/2008/03/13/44355.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/eXile/comments/commentRss/44355.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/eXile/services/trackbacks/44355.html</trackback:ping><description><![CDATA[<p>　　ＧＣＣ４.３发布了，终于可以试试传说中的C++0x, 尽管只是部分。对于新的语言特性，也尝试着了解了一下。<br>　　１）改变最大的语言特性就是右值引用了。花了半天去搞清楚什么是右值引用，对于std::move和std::forward这两个函数也蒙了好长时间。觉得这个东西似乎对一般的开发者没什么用处，除非你要开发一个Ｃ＋＋库。好象标准库的容器除了basic_string外，基本上都支持了这点。智能指针shared_ptr也支持了右值引用。为了提高效率，又增加了语言的复杂性，这大概就是c++的语言哲学吧。<br>　　２）可变参数模板。这个用来实现std::function，std::bind及std::tuple.<br>　　３）static_assert。这个自己实现一个也很容易。<br>　　４）decltype。就是以前的__typeof__。这次只不过是扶正了。<br>&nbsp;　　５）模板中＞＞可以连着写了。<br>　　６）函数模板也可以有缺省参数了。<br>　　７）。。。。<br>　　８）对于标准库的一些容器算法采用了并行处理。看来还是要尽可能多的使用标准库。<br><br>　　不过我编译了一个标准的HelloWorld（使用iostream），Debug&nbsp;版本的可执行文件竟然为3.5M，幸好Release下还没有增加太多。<br>&nbsp; 　　</p>
<img src ="http://www.cppblog.com/eXile/aggbug/44355.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eXile/" target="_blank">eXile</a> 2008-03-13 11:56 <a href="http://www.cppblog.com/eXile/archive/2008/03/13/44355.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计Qt风格的C++API (zt)</title><link>http://www.cppblog.com/eXile/archive/2008/02/18/42857.html</link><dc:creator>eXile</dc:creator><author>eXile</author><pubDate>Sun, 17 Feb 2008 16:50:00 GMT</pubDate><guid>http://www.cppblog.com/eXile/archive/2008/02/18/42857.html</guid><wfw:comment>http://www.cppblog.com/eXile/comments/42857.html</wfw:comment><comments>http://www.cppblog.com/eXile/archive/2008/02/18/42857.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/eXile/comments/commentRss/42857.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/eXile/services/trackbacks/42857.html</trackback:ping><description><![CDATA[<h1>设计Qt风格的C++API</h1>
<strong>
<p>作者Matthias Ettrich，译者Googol Lee，原文地址在<a href="http://doc.trolltech.com/qq/qq13-apis.html"><font color=#004faf>这里</font></a>。 </p>
</strong>
<blockquote><strong>
<p>在奇趣（Trolltech），为了改进Qt的开发体验，我们做了大量的研究。这篇文章里，我打算分享一些我们的发现，以及一些我们在设计Qt4时用到的原则，并且展示如何把这些原则应用到你的代码里。 </p>
</strong>
<ul>
    <li><a href="file:///C:/Documents%20and%20Settings/wujq/Local%20Settings/Temp/Rar$EX00.547/设计Qt风格的C++API.html#SixCharacteristicsOfGoodApis"><font color=#004faf>好的API的六个特性</font></a>
    <li><a href="file:///C:/Documents%20and%20Settings/wujq/Local%20Settings/Temp/Rar$EX00.547/设计Qt风格的C++API.html#TheConvenienceTrap"><font color=#004faf>便利陷阱</font></a>
    <li><a href="file:///C:/Documents%20and%20Settings/wujq/Local%20Settings/Temp/Rar$EX00.547/设计Qt风格的C++API.html#TheBooleanParameterTrap"><font color=#004faf>布尔参数陷阱</font></a>
    <li><a href="file:///C:/Documents%20and%20Settings/wujq/Local%20Settings/Temp/Rar$EX00.547/设计Qt风格的C++API.html#StaticPolymorphism"><font color=#004faf>静态多态</font></a>
    <li><a href="file:///C:/Documents%20and%20Settings/wujq/Local%20Settings/Temp/Rar$EX00.547/设计Qt风格的C++API.html#TheArtOfNaming"><font color=#004faf>命名的艺术</font></a>
    <li><a href="file:///C:/Documents%20and%20Settings/wujq/Local%20Settings/Temp/Rar$EX00.547/设计Qt风格的C++API.html#PointersOrReferences"><font color=#004faf>指针还是引用？</font></a>
    <li><a href="file:///C:/Documents%20and%20Settings/wujq/Local%20Settings/Temp/Rar$EX00.547/设计Qt风格的C++API.html#CaseStudyQprogressbar"><font color=#004faf>例子：QProgressBar</font></a>
    <li><a href="file:///C:/Documents%20and%20Settings/wujq/Local%20Settings/Temp/Rar$EX00.547/设计Qt风格的C++API.html#HowToGetApisRight"><font color=#004faf>如何把API设计好</font></a> </li>
</ul>
</blockquote>
<p>设计应用程序接口，API，是很难的。这是一门和设计语言同样难的艺术。这里可以选择太多的原则，甚至有很多原则和其他原则有矛盾。 </p>
<p>现在，计算机科学教育把很大的力气放在算法和数据结构上，而很少关注设计语言和框架背后的原则。这让应用程序员完全没有准备去面对越来越重要的任务：创造可重用的组件。 </p>
<p>在面向对象语言普及之前，可重用的通用代码大部分是由库提供者写的，而不是应用程序员。在Qt的世界里，这种状况有了明显的改善。在任何时候，用Qt编程就是写新的组件。一个典型的Qt应用程序至少都会有几个在程序中反复使用的自定义组件。一般来说，同样的组件会成为其他应用程序的一部分。KDE，K桌面环境，走得更远，用许多追加的库来扩展Qt，实现了数百个附加类。（一般来说，一个类就是一个可重用组件，原文这里没有写清楚。） </p>
<p>但是，一个好的，高效的C++ API是由什么组成的呢？是好还是坏，取决于很多因素——比如，手头的工作和特定的目标群体。好的API有很多特性，一些特性是大家都想要的，而另一些则是针对特定问题域的。 </p>
<a name=SixCharacteristicsOfGoodApis>
<h2>好的API的六个特性</h2>
</a>
<p>API是面向程序员的，用来描述提供给最终用户的GUI是什么样子。API中的P带表程序员（Programmer），而不是程序（Program），用来强调API是给程序员用的，给人类的程序员用的。 </p>
<p>我们坚信API应该是最小化且完整的，拥有清晰且简单的语义，直觉化，容易记忆，并且引导人写出易读的代码。 </p>
<ul>
    <li><strong>最小化：</strong>最小化的API是指一个类尽可能只拥有最少的公开成员且尽可能只拥有最少的类。这个原则可以让API更简单易懂，更好记，更容易除错，且更容易改变。
    <li><strong>完整的：</strong>完整的API是指要提供所有期望的功能。这个可能与最小化原则相冲突。另外，如果一个成员函数属于一个不应该属于的类，很多潜在的使用者都会找不到这个函数。
    <li><strong>拥有清晰且简单的语义：</strong>就像其他设计工作一样，你必须遵守最小惊奇原则（the principle of least surprise）。让常见的任务简单易行。不常见的工作可行，但不会让用户过分关注。解决特殊问题时，不要让解决方案没有必要的过度通用。（比如，Qt3中的<a href="http://doc.trolltech.com/3.3/qmimesourcefactory.html"><font color=#004faf>QMimeSourceFactory</font></a>可以通过调用QImageLoader来实现不同的API。）
    <li><strong>直觉化：</strong>就像电脑上的其他东西一样，API必须是直觉化的。不同的经验和背景会导致在判断什么是直觉而什么不是时不同的感觉。如果一个中级用户不读文档就可以使用（a semi-experienced user gets away without reading the documentation，没懂这里的get away该怎么翻译），并且一个程序员不懂API就可以理解缩写的代码，这种API就是直觉化的。
    <li><strong>易于记忆：</strong>让API易于记忆，使用统一且精确的命名方法。使用可识别的模式和概念，并且避免缩写。
    <li><strong>引导易读的代码（Lead to readable code）：</strong>代码一经写就，会读（并且除错和修改）多次。易读的代码可能会花点时间来写，但是可以节省产品周期中的其他时间。 </li>
</ul>
<p>最后，记住，不同类型的用户会用到API的不同部分。虽然简单的实例化一个Qt类是非常直觉化的，让资深专家在试图子类化之前读一遍文档，是很合理的。 </p>
<a name=TheConvenienceTrap>
<h2>便利陷阱</h2>
</a>
<p>这是个常见的误解：更好的API，用更少的代码完成一件事。永远记住代码一次写就，之后需要不断的阅读并理解。比如： </p>
<pre>    <a href="http://doc.trolltech.com/3.3/qslider.html"><font color=#004faf>QSlider</font></a> *slider = new <a href="http://doc.trolltech.com/3.3/qslider.html"><font color=#004faf>QSlider</font></a>(12, 18, 3, 13, Qt::Vertical,
0, "volume");
</pre>
<p>远比下面那样难读（甚至难写）： </p>
<pre>    <a href="http://doc.trolltech.com/3.3/qslider.html"><font color=#004faf>QSlider</font></a> *slider = new <a href="http://doc.trolltech.com/3.3/qslider.html"><font color=#004faf>QSlider</font></a>(Qt::Vertical);
slider-&gt;setRange(12, 18);
slider-&gt;setPageStep(3);
slider-&gt;setValue(13);
slider-&gt;setObjectName("volume");
</pre>
<a name=TheBooleanParameterTrap>
<h2>布尔参数陷阱</h2>
</a>
<p>布尔参数通常会导致不易读的代码。更进一步，给一个已经存在的函数加入一个布尔参数，这常常是个错误。在Qt里，一个传统的例子是repaint()，这个函数带有一个布尔参数，来标识是否擦除背景（默认擦除）。这让代码通常写成： </p>
<pre>    widget-&gt;repaint(false);
</pre>
<p>初学者很容易把这句话理解成&#8220;别重画&#8221;！ </p>
<p>这样做是考虑到布尔参数可以减少一个函数，避免代码膨胀。事实上，这反而增加了代码量。有多少Qt用户真的记住了下面三行程序都是做什么的？ </p>
<pre>    widget-&gt;repaint();
widget-&gt;repaint(true);
widget-&gt;repaint(false);
</pre>
<p>一个好一些的API可能看起来是这样： </p>
<pre>    widget-&gt;repaint();
widget-&gt;repaintWithoutErasing();
</pre>
<p>在Qt4里，我们重新设计了widget，使得用户不再需要不重画背景的重画widget，来解决这个问题。Qt4原生支持双缓存，废掉了这个特性。 </p>
<p>这里还有一些例子： </p>
<pre>    widget-&gt;setSizePolicy(<a href="http://doc.trolltech.com/4.0/qsizepolicy.html"><font color=#004faf>QSizePolicy</font></a>::Fixed,
<a href="http://doc.trolltech.com/4.0/qsizepolicy.html"><font color=#004faf>QSizePolicy</font></a>::Expanding, true);
textEdit-&gt;insert("Where's Waldo?", true, true, false);
<a href="http://doc.trolltech.com/3.3/qregexp.html"><font color=#004faf>QRegExp</font></a> rx("moc_*.c??", false, true);
</pre>
<p>一个显而易见的解决方法是，使用枚举类型代替布尔参数。这正是我们在Qt4中<a href="http://doc.trolltech.com/3.3/qstring.html"><font color=#004faf>QString</font></a>大小写敏感时的处理方法。比较： </p>
<pre>    str.replace("%USER%", user, false);               // Qt 3
str.replace("%USER%", user, Qt::CaseInsensitive); // Qt 4
</pre>
<a name=StaticPolymorphism>
<h2>静态多态</h2>
</a>
<p>相似的类应该含有相似的API。在必要的时候——就是说，需要使用运行时多态的时候——这可以通过继承实现。但是多态依旧会发生在设计时期。比如，如果你用<a href="http://doc.trolltech.com/3.3/qlistbox.html"><font color=#004faf>QListBox</font></a>代替<a href="http://doc.trolltech.com/3.3/qcombobox.html"><font color=#004faf>QComboBox</font></a>，或者用<a href="http://doc.trolltech.com/4.0/qslider.html"><font color=#004faf>QSlider</font></a>代替<a href="http://doc.trolltech.com/4.0/qspinbox.html"><font color=#004faf>QSpinBox</font></a>，你会发现相似的API使这种替换非常容易。这就是我们所说的&#8220;静态多态&#8221;。 </p>
<p>静态多态也使API和程序模式更容易记忆。作为结论，一组相关类使用相似的API，有时要比给每个类提供完美的单独API，要好。 </p>
<p>（译注：C++ 0x将要引入的concept，就是静态多态的语法层实现。这个要比单独的函数名相似更强大且易用。） </p>
<a name=TheArtOfNaming>
<h2>命名的艺术</h2>
</a>
<p>命名，大概是设计API时唯一最重要的问题了。该怎么称呼这个类？成员函数该叫什么？ </p>
<h3>通用的命名规则</h3>
<p>一些规则通常对所有名字都是有用的。首先，就像我之前提到的，别用缩写。甚至很明显的缩写，比如&#8220;prev&#8221;表示&#8220;previous&#8221;从长远看也是不划算的，因为用户必须记住哪些词是缩写。 </p>
<p>如果API本身不一致，事情自然会变得很糟糕，比如， Qt3有activatePreviousWindow()和fetchPrev()。坚持&#8220;没有缩写&#8221;的规则更容易创建一致的API。 </p>
<p>另一个重要但更加微妙的规则是，在设计类的时候，必须尽力保证子类命名空间的干净。在Qt3里，没有很好的遵守这个规则。比如，拿<a href="http://doc.trolltech.com/3.3/qtoolbutton.html"><font color=#004faf>QToolButton</font></a>来举例。如果你在Qt3里，对一个<a href="http://doc.trolltech.com/3.3/qtoolbutton.html"><font color=#004faf>QToolButton</font></a>调用name()、caption()、text()或者textLabel()，你希望做什么呢？你可以在Qt Designer里拿QToolButton试试： </p>
<ul>
    <li>name属性继承自<a href="http://doc.trolltech.com/3.3/qobject.html"><font color=#004faf>QObject</font></a>，表示一个对象用于除错和测试的内部名字。
    <li>caption属性继承自<a href="http://doc.trolltech.com/3.3/qwidget.html"><font color=#004faf>QWidget</font></a>，表示窗口的标题，这个标题在视觉上对<a href="http://doc.trolltech.com/3.3/qtoolbutton.html"><font color=#004faf>QToolButton</font></a>没有任何意义，因为他们总是跟随父窗口而创建。
    <li>text属性继承自<a href="http://doc.trolltech.com/3.3/qbutton.html"><font color=#004faf>QButton</font></a>，一般情况下是按钮上现实的文字，除非useTextLabel为真。
    <li>textLabel在<a href="http://doc.trolltech.com/3.3/qtoolbutton.html"><font color=#004faf>QToolButton</font></a>里声明，并且在useTextLabel为真时显示在按钮上。 </li>
</ul>
<p>由于对可读性的关注，name在Qt4里被称作objectName，caption变成了windowsTitle，而在<a href="http://doc.trolltech.com/3.3/qtoolbutton.html"><font color=#004faf>QToolButton</font></a>里不再有单独的textLabel属性。 </p>
<h3>给类命名</h3>
<p>标识一组类而不是单独给每个类找个恰当的名字。比如，Qt4里所有模式感知项目的视图类（model-aware item view classes）都拥有-View的后缀（<a href="http://doc.trolltech.com/4.0/qlistview.html"><font color=#004faf>QListView</font></a>、<a href="http://doc.trolltech.com/4.0/qtableview.html"><font color=#004faf>QTableView</font></a>和<a href="http://doc.trolltech.com/4.0/qtreeview.html"><font color=#004faf>QTreeView</font></a>），并且对应基于项目的类都用后缀-Widget代替（<a href="http://doc.trolltech.com/4.0/qlistwidget.html"><font color=#004faf>QListWidget</font></a>、<a href="http://doc.trolltech.com/4.0/qtablewidget.html"><font color=#004faf>QTableWidget</font></a>和<a href="http://doc.trolltech.com/4.0/qtreewidget.html"><font color=#004faf>QTreeWidget</font></a>）。 </p>
<h3>给枚举类型及其值命名</h3>
<p>当声明枚举时，时刻记住，在C++（不像Java和C#）中，使用枚举值不需要类型信息。下面的例子演示了给枚举值起个太过常用的名字所引起的危害： </p>
<pre>    namespace Qt
{
enum Corner { TopLeft, BottomRight, ... };
enum CaseSensitivity { Insensitive, Sensitive };
...
};
tabWidget-&gt;setCornerWidget(widget, Qt::TopLeft);
str.indexOf("$(QTDIR)", Qt::Insensitive);
</pre>
<p>在最后一行，Insensitive是什么意思？一个用于命名枚举值的指导思想是，在每个枚举值里，至少重复一个枚举类型名中的元素： </p>
<pre>    namespace Qt
{
enum Corner { TopLeftCorner, BottomRightCorner, ... };
enum CaseSensitivity { CaseInsensitive,
CaseSensitive };
...
};
tabWidget-&gt;setCornerWidget(widget, Qt::TopLeftCorner);
str.indexOf("$(QTDIR)", Qt::CaseInsensitive);
</pre>
<p>当枚举值可以用&#8220;或&#8221;连接起来当作一个标志时，传统的做法是将&#8220;或&#8221;的结果作为一个int保存，这不是类型安全的。Qt4提供了一个模板类 <a href="http://doc.trolltech.com/4.0/qflags.html"><font color=#004faf>QFlags</font></a>&lt;T&gt;来实现类型安全，其中T是个枚举类型。为了方便使用，Qt为很多标志类名提供了typedef，所以你可以使用类型 Qt::Alignment代替<a href="http://doc.trolltech.com/4.0/qflags.html"><font color=#004faf>QFlags</font></a>&lt;Qt::AlignmentFlag&gt;。 </p>
<p>为了方便，我们给枚举类型单数的名字（这样表示枚举值一次只能有一个标志），而&#8220;标志&#8221;则使用复数名字。比如： </p>
<pre>    enum RectangleEdge { LeftEdge, RightEdge, ... };
typedef <a href="http://doc.trolltech.com/4.0/qflags.html"><font color=#004faf>QFlags</font></a>&lt;RectangleEdge&gt; RectangleEdges;
</pre>
<p>有些情况下，&#8220;标志&#8220;类使用了单数的名字。这时，枚举类使用-Flag做后缀： </p>
<pre>    enum AlignmentFlag { AlignLeft, AlignTop, ... };
typedef <a href="http://doc.trolltech.com/4.0/qflags.html"><font color=#004faf>QFlags</font></a>&lt;AlignmentFlag&gt; Alignment;
</pre>
<p>（这里为啥不是把&#8221;标志&#8220;类用-Flag做后缀，而是把枚举值做后缀呢？感觉有点混淆&#8230;&#8230;） </p>
<h3>给函数和参数命名</h3>
<p>给函数命名的一个规则是，名字要明确体现出这个函数是否有副作用。在Qt3，常数函数<a href="http://doc.trolltech.com/3.3/qstring.html"><font color=#004faf>QString</font></a>::simplifyWhiteSpace()违反了这个原则，因为它返回类一个<a href="http://doc.trolltech.com/3.3/qstring.html"><font color=#004faf>QString</font></a>实例，而不是像名字所提示的那样，更改了调用这个函数的实例本身。在Qt4，这个函数被重命名为<a href="http://doc.trolltech.com/3.3/qstring.html"><font color=#004faf>QString</font></a>::simplified()。 </p>
<p>参数名是程序员的重要信息来源，虽然在使用API时，并不直接展示在代码里。由于现代IDE在程序员写代码时可以自动显示参数名（就是自动感知或者自动补全之类的功能），值得花时间给头文件里声明的参数一个合适的名字，并且在文档中也使用相同的名字。 </p>
<h3>给布尔值设置函数（Setter）、提取函数（Getter）和属性命名</h3>
<p>给布尔属性的设置函数和提取函数一个合适的名字，总是非常痛苦的。提取函数应该叫做checked()还是isChecked()？scrollBarsEnabled()还是areScrollBarEnabled()? </p>
<p>在Qt4里，我们使用下列规则命名提取函数： </p>
<ul>
    <li>形容类的属性使用is-前缀。比如：
    <ul>
        <li><tt>isChecked()</tt>
        <li><tt>isDown()</tt>
        <li><tt>isEmpty()</tt>
        <li><tt>isMovingEnable()</tt> </li>
    </ul>
    另外，应用到复数名词的形容类属性没有前缀：
    <ul>
        <li><tt>scrollBarsEnabled()</tt>，而不是<tt>areScrollBarsEnabled()</tt> </li>
    </ul>
    <li>动词类的属性不使用前缀，且不使用第三人称（-s）：
    <ul>
        <li><tt>acceptDrops()</tt>，而不是<tt>acceptsDrops()</tt>
        <li><tt>allColumnsShowFocus()</tt> </li>
    </ul>
    <li>名词类的属性，通常没有前缀：
    <ul>
        <li><tt>autoCompletion()</tt>，而不是<tt>isAutoCompletion()</tt>
        <li><tt>boundaryChecking()</tt> </li>
    </ul>
    有时，没有前缀就会引起误解，这种情况使用前缀is-：
    <ul>
        <li><tt>isOpenGLAvailable()</tt>，而不是<tt>openGL()</tt>
        <li><tt>isDialog()</tt>，而不是<tt>dialog()</tt> </li>
    </ul>
    （通过调用dialogue()方法，正常情况下会期望返回一个<a href="http://doc.trolltech.com/4.0/qdialog.html"><font color=#004faf>QDialog</font></a>*的实例。） </li>
</ul>
<p>设置函数名字继承自提取函数名，只是移掉了所有前缀，并使用set-做前缀，比如：setDown()还有setScrollBarsEnabled()。属性的名字与提取函数相同，只是去掉了前缀。 </p>
<a name=PointersOrReferences>
<h2>指针还是引用？</h2>
</a>
<p>传出参数的最佳选择是什么，指针还是引用？ </p>
<pre>    void getHsv(int *h, int *s, int *v) const
void getHsv(int &amp;h, int &amp;s, int &amp;v) const
</pre>
<p>大部分C++书推荐在能用引用的地方就用引用，这是因为一般认为引用比指针更&#8220;安全且好用&#8221;。然而，在奇趣（Trolltech），我们倾向使用指针，因为这让代码更易读。比较： </p>
<pre>    color.getHsv(&amp;h, &amp;s, &amp;v);
color.getHsv(h, s, v);
</pre>
<p>只有第一行能清楚的说明，在函数调用后，h、s和v将有很大几率被改动。 </p>
<a name=CaseStudyQprogressbar>
<h2>例子：QProgressBar</h2>
</a>
<p>为了展示如何实际应用这些概念，我们将学习Qt3中的API <a href="http://doc.trolltech.com/3.3/qprogressbar.html"><font color=#004faf>QProgressBar</font></a>并和Qt4里相通的API做比较。在Qt3里： </p>
<pre>    class <a href="http://doc.trolltech.com/3.3/qprogressbar.html"><font color=#004faf>QProgressBar</font></a> : public <a href="http://doc.trolltech.com/3.3/qwidget.html"><font color=#004faf>QWidget</font></a>
{
...
public:
int totalSteps() const;
int progress() const;
const <a href="http://doc.trolltech.com/3.3/qstring.html"><font color=#004faf>QString</font></a> &amp;progressString() const;
bool percentageVisible() const;
void setPercentageVisible(bool);
void setCenterIndicator(bool on);
bool centerIndicator() const;
void setIndicatorFollowsStyle(bool);
bool indicatorFollowsStyle() const;
public slots:
void reset();
virtual void setTotalSteps(int totalSteps);
virtual void setProgress(int progress);
void setProgress(int progress, int totalSteps);
protected:
virtual bool setIndicator(<a href="http://doc.trolltech.com/3.3/qstring.html"><font color=#004faf>QString</font></a> &amp;progressStr,
int progress,
int totalSteps);
...
};
</pre>
<p>API相当复杂，且不统一。比如，仅从名字reset()并不能理解其作用，setTotalSteps()和setProgress()是紧耦合的。 </p>
<p>改进API的关键，是注意到<a href="http://doc.trolltech.com/3.3/qprogressbar.html"><font color=#004faf>QProgressBar</font></a>和Qt4的<a href="http://doc.trolltech.com/4.0/qabstractspinbox.html"><font color=#004faf>QAbstractSpinBox</font></a>类及其子类<a href="http://doc.trolltech.com/4.0/qspinbox.html"><font color=#004faf>QSpinBox</font></a>，<a href="http://doc.trolltech.com/4.0/qslider.html"><font color=#004faf>QSlider</font></a>和<a href="http://doc.trolltech.com/4.0/qdial.html"><font color=#004faf>QDial</font></a>很相似。解决方法？用minimum、maximum和value代替progress和totalSteps。加入alueChanged()信号。加入setRange()函数。 </p>
<p>之后观察progressString、percentage和indicator实际都指一个东西：在进度条上显示的文字。一般来说文字是百分比信息，但是也可以使用setIndicator()设为任意字符。下面是新的API： </p>
<pre>    virtual <a href="http://doc.trolltech.com/3.3/qstring.html"><font color=#004faf>QString</font></a> text() const;
void setTextVisible(bool visible);
bool isTextVisible() const;
</pre>
<p>默认的文字信息是百分比信息。文字信息可以藉由重新实现text()而改变。 </p>
<p>在Qt3 API中，setCenterIndicator()和setIndicatorFollowStyle()是两个影响对齐的函数。他们可以方便的由一个函数实现，setAlignment()： </p>
<pre>    void setAlignment(Qt::Alignment alignment);
</pre>
<p>如果程序员不调用setAlignment()，对齐方式基于当前的风格。对于基于Motif的风格，文字将居中显示；对其他风格，文字将靠在右边。 </p>
<p>这是改进后的<a href="http://doc.trolltech.com/3.3/qprogressbar.html"><font color=#004faf>QProgressBar</font></a> API： </p>
<pre>    class <a href="http://doc.trolltech.com/3.3/qprogressbar.html"><font color=#004faf>QProgressBar</font></a> : public <a href="http://doc.trolltech.com/3.3/qwidget.html"><font color=#004faf>QWidget</font></a>
{
...
public:
void setMinimum(int minimum);
int minimum() const;
void setMaximum(int maximum);
int maximum() const;
void setRange(int minimum, int maximum);
int value() const;
virtual <a href="http://doc.trolltech.com/3.3/qstring.html"><font color=#004faf>QString</font></a> text() const;
void setTextVisible(bool visible);
bool isTextVisible() const;
Qt::Alignment alignment() const;
void setAlignment(Qt::Alignment alignment);
public slots:
void reset();
void setValue(int value);
signals:
void valueChanged(int value);
...
};
</pre>
<a name=HowToGetApisRight>
<h2>如何把API设计好（原文是How to Get APIs Right，我总想成We do APIs right&#8230;&#8230;）</h2>
</a>
<p>API需要质量保证。第一个修订版不可能是正确的；你必须做测试。写些用例：看看那些使用了这些API的代码，并验证代码是否易读。 </p>
<p>其他的技巧包括让别的人分别在有文档和没有文档的情况下，使用这些API；或者为API类写文档（包括类的概述和独立的函数）。 </p>
<p>当你卡住时，写文档也是一种获得好名字的方法：仅仅是尝试把条目（类，函数，枚举值，等等呢个）写下来并且使用你写的第一句话作为灵感。如果你不能找到一个精确的名字，这常常说明这个条目不应该存在。如果所有前面的事情都失败了并且你确认这个概念的存在，发明一个新名字。毕竟，&#8220;widget&#8221;、 &#8220;event&#8221;、&#8220;focus&#8221;和&#8220;buddy&#8221;这些名字就是这么来的。 </p>
<img src ="http://www.cppblog.com/eXile/aggbug/42857.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eXile/" target="_blank">eXile</a> 2008-02-18 00:50 <a href="http://www.cppblog.com/eXile/archive/2008/02/18/42857.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>vector的有序化操作</title><link>http://www.cppblog.com/eXile/archive/2008/01/29/42104.html</link><dc:creator>eXile</dc:creator><author>eXile</author><pubDate>Tue, 29 Jan 2008 05:13:00 GMT</pubDate><guid>http://www.cppblog.com/eXile/archive/2008/01/29/42104.html</guid><wfw:comment>http://www.cppblog.com/eXile/comments/42104.html</wfw:comment><comments>http://www.cppblog.com/eXile/archive/2008/01/29/42104.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/eXile/comments/commentRss/42104.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/eXile/services/trackbacks/42104.html</trackback:ping><description><![CDATA[　　在有些情况下，需要用到一个有序的vector。它的有序操作有三种：查找，插入，删除。<br>　　<br>　　插入实现：
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">typename</span><span style="COLOR: #000000">&nbsp;Container</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>inline&nbsp;void&nbsp;ordered_insert(Container</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;c,　&nbsp;</span><span style="COLOR: #0000ff">typename</span><span style="COLOR: #000000">&nbsp;Container::value_type&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;t)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;c.insert(std::upper_bound(c.begin(),&nbsp;c.end(),&nbsp;t),&nbsp;t);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">typename</span><span style="COLOR: #000000">&nbsp;Container,&nbsp;</span><span style="COLOR: #0000ff">typename</span><span style="COLOR: #000000">&nbsp;Cmp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>inline&nbsp;void&nbsp;ordered_insert(Container</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;c,　</span><span style="COLOR: #0000ff">typename</span><span style="COLOR: #000000">&nbsp;Container::value_type&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;t,　Cmp&nbsp;cmp)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;c.insert(std::upper_bound(c.begin(),&nbsp;c.end(),&nbsp;t,&nbsp;cmp),&nbsp;t);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
　　<br>　　删除实现：
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">typename</span><span style="COLOR: #000000">&nbsp;Container,&nbsp;</span><span style="COLOR: #0000ff">typename</span><span style="COLOR: #000000">&nbsp;It</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>inline&nbsp;void&nbsp;erase_range(Container</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;c,&nbsp;std::pair</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">It,&nbsp;It</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;r)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;c.erase(r.first,&nbsp;r.second);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">typename</span><span style="COLOR: #000000">&nbsp;Container</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>inline&nbsp;void&nbsp;ordered_erase(Container</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;c,&nbsp;　</span><span style="COLOR: #0000ff">typename</span><span style="COLOR: #000000">&nbsp;Container::value_type&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;t)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;erase_range(c,&nbsp;std::equal_range(c.begin(),&nbsp;c.end(),&nbsp;t));<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">typename</span><span style="COLOR: #000000">&nbsp;Container,&nbsp;</span><span style="COLOR: #0000ff">typename</span><span style="COLOR: #000000">&nbsp;T,&nbsp;</span><span style="COLOR: #0000ff">typename</span><span style="COLOR: #000000">&nbsp;Cmp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>inline&nbsp;void&nbsp;ordered_erase(Container</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;c,&nbsp;T&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;t,&nbsp;Cmp&nbsp;cmp)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;erase_range(c,&nbsp;std::equal_range(c.begin(),&nbsp;c.end(),&nbsp;t,&nbsp;cmp));<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<br>　　查找可通过binary_search, lower_bound, upper_bound, 或者equal_range实现。如果要实现类似map的关键字搜索，有一个技巧，就是用比较函数进行重载，比如学生要按学号查找，则用以下定义：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">struct&nbsp;Student<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;id;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;std::</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;name;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;LessThan<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bool&nbsp;operator()&nbsp;(Student&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;x,&nbsp;Student&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;y)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;x.id&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;y.id;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bool&nbsp;operator()&nbsp;(Student&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;x,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;id)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;x.id&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;id;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bool&nbsp;operator()&nbsp;(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;id,&nbsp;Student&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;y)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;id&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;y.id;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;};<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>};<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<br>查找学号为5的学生：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">std::vector&lt;Student&gt; students;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><span style="COLOR: #000000">bool&nbsp;exist&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;std::binary_search(students.begin(),&nbsp;students.end(),&nbsp;</span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">,&nbsp;Student::LessThan());</span></div>
<br>删除学号为5的学生：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">ordered_erase(students,&nbsp;</span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">,&nbsp;Student::LessThan());</span></div>
<br>
<img src ="http://www.cppblog.com/eXile/aggbug/42104.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eXile/" target="_blank">eXile</a> 2008-01-29 13:13 <a href="http://www.cppblog.com/eXile/archive/2008/01/29/42104.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>我的signal/slot实现（修订版）</title><link>http://www.cppblog.com/eXile/archive/2008/01/09/40782.html</link><dc:creator>eXile</dc:creator><author>eXile</author><pubDate>Wed, 09 Jan 2008 02:59:00 GMT</pubDate><guid>http://www.cppblog.com/eXile/archive/2008/01/09/40782.html</guid><wfw:comment>http://www.cppblog.com/eXile/comments/40782.html</wfw:comment><comments>http://www.cppblog.com/eXile/archive/2008/01/09/40782.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/eXile/comments/commentRss/40782.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/eXile/services/trackbacks/40782.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 自从掌握了signal/slot机制后，它已经变成了我在设计中一种必不可少的方法，如何在非ＱＴ环境中使用这种机制，也是我一直在考虑的问题。目前的这个版本，相对来说还是比较满意的，而且个人认为它要优于Boost::signal的实现。&nbsp;&nbsp;<a href='http://www.cppblog.com/eXile/archive/2008/01/09/40782.html'>阅读全文</a><img src ="http://www.cppblog.com/eXile/aggbug/40782.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eXile/" target="_blank">eXile</a> 2008-01-09 10:59 <a href="http://www.cppblog.com/eXile/archive/2008/01/09/40782.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>QT中异形窗口的绘制</title><link>http://www.cppblog.com/eXile/archive/2007/12/09/38084.html</link><dc:creator>eXile</dc:creator><author>eXile</author><pubDate>Sun, 09 Dec 2007 07:06:00 GMT</pubDate><guid>http://www.cppblog.com/eXile/archive/2007/12/09/38084.html</guid><wfw:comment>http://www.cppblog.com/eXile/comments/38084.html</wfw:comment><comments>http://www.cppblog.com/eXile/archive/2007/12/09/38084.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/eXile/comments/commentRss/38084.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/eXile/services/trackbacks/38084.html</trackback:ping><description><![CDATA[<br>　　这里讨论的只是Windows平台上的实现。<br>　　在ＱＴ中绘制异形窗口，只要设定 windowFlag 为 CustomizeWindowHint，再结合setMask()就可以做出各种奇形怪状的窗口。相对来说比较麻烦的, 是进行窗口拖动和缩放的处理。<br>　　在 Windows SDK 和 MFC　中比较容易，只要处理 WM_NCHITTEST，返回相应的测试值就可以了。幸运的是，ＱＴ中也提供了直接处理各平台消息的方法，在 Windows下只需要重载winEvent方法。<br>&nbsp;<br>　　下面给出了示例代码：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">// include &lt;windows.h&gt;<br><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">bool&nbsp;MyDialog::winEvent(MSG</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;msg,&nbsp;</span><span style="COLOR: #0000ff">long</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;result)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;captionHeight&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">25</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;frameWidth&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">6</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(msg</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">message&nbsp;!</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;WM_NCHITTEST)&nbsp;return&nbsp;</span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;QPoint&nbsp;pos&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;mapFromGlobal(QCursor::pos());<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;w&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;width();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;h&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;height();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(QRect(frameWidth,&nbsp;captionHeight,&nbsp;w</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">frameWidth</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">frameWidth,&nbsp;h</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">captionHeight</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">frameWidth).contains(pos))<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">result&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;HTCLIENT;<br></span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(QRect(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;w,&nbsp;captionHeight).contains(pos))<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">result&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;HTCAPTION;<br></span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(QRect(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;captionHeight,&nbsp;frameWidth,&nbsp;h</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">captionHeight</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">frameWidth).contains(pos))<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">result&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;HTLEFT;<br></span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(QRect(w</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">frameWidth,&nbsp;captionHeight,&nbsp;frameWidth,&nbsp;h</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">captionHeight</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">frameWidth).contains(pos))<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">result&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;HTRIGHT;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br><span style="COLOR: #0000ff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;</span> (QRect(frameWidth, h-frameWidth, w-frameWidth-frameWidth, frameWidth).contains(pos))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;*result = HTBOTTOM;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(QRect(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;h</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">frameWidth,&nbsp;frameWidth,&nbsp;frameWidth).contains(pos))<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">result&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;HTBOTTOMLEFT;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(QRect(w</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">frameWidth,&nbsp;h</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">frameWidth,&nbsp;frameWidth,&nbsp;frameWidth).contains(pos))<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">result&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;HTBOTTOMRIGHT;<br></span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<img src ="http://www.cppblog.com/eXile/aggbug/38084.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eXile/" target="_blank">eXile</a> 2007-12-09 15:06 <a href="http://www.cppblog.com/eXile/archive/2007/12/09/38084.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>悬挂指针与boost::weak_ptr</title><link>http://www.cppblog.com/eXile/archive/2007/10/11/33936.html</link><dc:creator>eXile</dc:creator><author>eXile</author><pubDate>Thu, 11 Oct 2007 03:49:00 GMT</pubDate><guid>http://www.cppblog.com/eXile/archive/2007/10/11/33936.html</guid><wfw:comment>http://www.cppblog.com/eXile/comments/33936.html</wfw:comment><comments>http://www.cppblog.com/eXile/archive/2007/10/11/33936.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/eXile/comments/commentRss/33936.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/eXile/services/trackbacks/33936.html</trackback:ping><description><![CDATA[<p>&nbsp;　　与内存泄露相比，C++最令人头痛的问题是内存越界，而内存越界很多情况下是由于悬挂指针引起的。　　<br>　　假设一个指针变量： <br>　　Object * ptr;<br>　　使用ptr时，我们除了要判断ptr是否为0以外，还要怀疑它指向的对象是否有效，是不是已经在别的地方被销毁了。我们希望当它指向的对象被销毁时，ptr被自动置为0。<br>　　显然，C++没有这种机制，但是，可以借助于boost::weak_ptr做到这一点。<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">inline&nbsp;void&nbsp;null_deleter(void&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>class&nbsp;X<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;shared_ptr</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">X</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;this_;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;i_;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">explicit</span><span style="COLOR: #000000">&nbsp;X(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;i):&nbsp;this_(this,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">null_deleter),&nbsp;i_(i)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;X(X&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;rhs):&nbsp;this_(this,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">null_deleter),&nbsp;i_(rhs.i_)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;X&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;operator</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">(X&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;rhs)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i_&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;rhs.i_;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;weak_ptr</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">X</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;weak_this()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;{&nbsp;return&nbsp;this_;&nbsp;}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>};<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br>&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<br>定义变量：<br>weak_ptr&lt;X&gt; ptr = x.weak_this();&nbsp; // x为一个X&nbsp;对象&nbsp;<br><br>则当 x 被销毁时，ptr 被自动置为无效。使用方法如下：<br><br>if ( shard_ptr&lt;X&gt;&nbsp; safePtr&nbsp; = ptr.lock() )&nbsp; safePtr-&gt;do_something();<br><br>这种办法用于单线程中，因为 x&nbsp;&nbsp;对象可能是基于栈分配的。如果需要在多线程中访问X对象，那么最好的办法还是使用shared_ptr 来管理对象的生命期。这样的话，对于safePtr, 可以保证在 safePtr 的生命期内，它所指向的对象不会被其它线程删除。<br>
<img src ="http://www.cppblog.com/eXile/aggbug/33936.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eXile/" target="_blank">eXile</a> 2007-10-11 11:49 <a href="http://www.cppblog.com/eXile/archive/2007/10/11/33936.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>D语言与C++</title><link>http://www.cppblog.com/eXile/archive/2007/09/14/32187.html</link><dc:creator>eXile</dc:creator><author>eXile</author><pubDate>Thu, 13 Sep 2007 18:26:00 GMT</pubDate><guid>http://www.cppblog.com/eXile/archive/2007/09/14/32187.html</guid><wfw:comment>http://www.cppblog.com/eXile/comments/32187.html</wfw:comment><comments>http://www.cppblog.com/eXile/archive/2007/09/14/32187.html#Feedback</comments><slash:comments>19</slash:comments><wfw:commentRss>http://www.cppblog.com/eXile/comments/commentRss/32187.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/eXile/services/trackbacks/32187.html</trackback:ping><description><![CDATA[<p>　　无意中听说了还有一种Ｄ语言，发现这Ｄ还真不赖，简直一个改良的C++高级语言版，兼具Ｃ＋＋和Java的优点，比那遥遥无期的Ｃ＋＋0X 要爽得多。<br>　　花了一个晚上，粗浅得了解了一下，感觉最强烈的有以下几点：<br><br>　　（１）超快的编译速度：编译几百个文件，只要３，４秒，估计Ｃ＋＋要半个小时吧。这是因为它的Module机制实在是比Ｃ＋＋的include机制强太多了。<br><br>　　（２）与Ｃ兼容策略：只与Ｃ接口兼容，这样既能利用现有的Ｃ资源，又不引入Ｃ的低级特征。这一点要比Ｃ＋＋的完全兼容策略好多了。这样，Linus大牛也不用叫喊：&#8220;你们这些搞Ｃ＋＋的家伙不要往我这Ｃ阵营里挤&#8221;。弄得好多人马上说Ｃ＋＋高不成低不就什么的。<br><br>　　（３）完美的宏替代者：Mixin　　<br>&nbsp;<br>&nbsp;　　（４）对象既可以由gc管理，也可以手动管理，倒是和C++0x有些像。 所以还可以结合析构函数实现ＲＡＩＩ，这一点ＪＡＶＡ是没有办法的（Java只能用丑陋的try catch块来解决这个问题）。<br><br>　　（５）很多新的特征：unittest,　不变式，contract programming, 　简单的模板用法。。。<br><br>说了这么多好处，再说一下Ｄ现在的最大问题：<br>　　对于现在Ｄ语言的发展，既没有一家成熟的商业公司支持，也没有一个有效的开源社区维护，它的设计完全掌握在设计者一个人手中，它的核心代码也没有完全开源，这使它的前景呈现出一些不稳定的因素。如果要用它进行商业开发的话，还是有点为时过早。<br>　　想起了Borland和CodeGear，与其弄什么Turbo C++，还不如去支持这个Ｄ。。。<br>　　又开始ＹＹ了，睡了。。。<br></p>
<img src ="http://www.cppblog.com/eXile/aggbug/32187.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eXile/" target="_blank">eXile</a> 2007-09-14 02:26 <a href="http://www.cppblog.com/eXile/archive/2007/09/14/32187.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>