﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-游戏人生</title><link>http://www.cppblog.com/Fox/</link><description>游戏人生 != ( 人生 == 游戏 )</description><language>zh-cn</language><lastBuildDate>Sat, 04 Jul 2009 07:31:06 GMT</lastBuildDate><pubDate>Sat, 04 Jul 2009 07:31:06 GMT</pubDate><ttl>60</ttl><item><title>设计模式（四）&amp;mdash;&amp;mdash;Template Method</title><link>http://www.cppblog.com/Fox/archive/2009/02/11/73420.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Tue, 10 Feb 2009 17:46:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2009/02/11/73420.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/73420.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2009/02/11/73420.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/73420.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/73420.html</trackback:ping><description><![CDATA[<p>在一个稍微上规模（怎么也有几十个类吧）的C++程序中，继承和组合的使用比比皆是。虽然GoF提出了OOD的两个原则，第二个谓之『<strong>优先使用对象组合，而不是继承</strong>』，但这绝不意味着不使用继承，正因如此，第一个原则才是『<strong>针对接口编程，而不是针对实现编程</strong>』，这两个原则清楚的表达了软件工程中『<strong>低耦合</strong>』的思想。</p> <p>模板方法（Template Method）的意图正是『<strong>定义一个操作中的算法的框架，而将一些步骤延迟到子类中</strong>』。</p> <p>注意，这里有个关键词『一些』，既然是『一些』，就意味着父类的的接口中已经实现了『一些』步骤，否则，父类便只提供了抽象接口。</p> <p>这一情况是我们在编码时时常遇到的，父类实现了部分算法中的通用行为，子类根据自己的需求可对其进行必要扩充。</p> <p><code>class CBase<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; // Default done<br>&nbsp;&nbsp;&nbsp; virtual void Operation(void)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br>&nbsp;&nbsp;&nbsp; }<br>}; </p> <p>class CDerive :<br>&nbsp;&nbsp;&nbsp; public CBase<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; virtual void Operation(void)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; switch( ... )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case A: ...<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case B: ...<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case c: ...<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; default:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CBase::Operation();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>};</code></p> <p>因为对父类的不了解或是对子类的太了解，你以为<code>CDerive::Operation()</code>做了足够多，不需要<code>CBase::Operation()</code>，但实际上仍然需要的情况总在发生。</p> <p>换一种方式，把<code>Operation()</code>作为模板方法，把<code>DoOperation()</code>作为可扩展的接口提供给子类实现：</p> <p><code>class CBase<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; void SetFocus(void) { ... }<br>&nbsp;&nbsp;&nbsp; void ResetFocus(void) { ... }<br>&nbsp;&nbsp;&nbsp; // Call by user<br>&nbsp;&nbsp;&nbsp; void Operation(void)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SetFocus();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DoOperation();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ResetFocus();<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; // Default done<br>&nbsp;&nbsp;&nbsp; virtual void DoOperation(void) = 0;<br>};  <p>class CDerive :<br>&nbsp;&nbsp;&nbsp; public CBase<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; virtual void DoOperation(void)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br>&nbsp;&nbsp;&nbsp; }<br>};</code></p> <p>模板方法只是提供了一个简单的封装技巧，当然不是所有的虚接口都这么写:)。</p> <hr>  <p>更多内容请移步<a href="http://www.yulefox.com" target="_blank">我的个人主页</a>。</p><img src ="http://www.cppblog.com/Fox/aggbug/73420.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2009-02-11 01:46 <a href="http://www.cppblog.com/Fox/archive/2009/02/11/73420.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VS2005断点失效的问题</title><link>http://www.cppblog.com/Fox/archive/2009/01/04/71110.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Sun, 04 Jan 2009 03:04:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2009/01/04/71110.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/71110.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2009/01/04/71110.html#Feedback</comments><slash:comments>12</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/71110.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/71110.html</trackback:ping><description><![CDATA[<p>VS2005下使用VC，部分断点无效，显示『当前不会命中断点。还没有为该文档加载任何符号』。</p> <p>试过以下一些方法：</p> <p>1、无效断点所在的项目和启动项目的设置：项目-&gt;属性-&gt;配置属性-&gt;C/C++-&gt;常规-&gt;调试信息格式，这里不能为『禁用』；</p> <p>2、项目-&gt;属性-&gt;配置属性-&gt;链接器-&gt;调试-&gt;生成调试信息，这里设为『是』；</p> <p>3、C/C++-&gt;优化-&gt;优化选择『禁用』；</p> <p>4、删除解决方案下的.ncb文件；</p> <p>5、工具-&gt;选项-&gt;调试-&gt;『要求源文件与原始版本完成匹配』去掉勾；</p> <p>6、最后在上述设置的情况下，重新编译整个解决方案；</p> <p>7、回过头来，发现原来是一段不会被执行到的代码……</p>看来，除了VS本身会有bug，自己的代码还是要多检查一下。<img src ="http://www.cppblog.com/Fox/aggbug/71110.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2009-01-04 11:04 <a href="http://www.cppblog.com/Fox/archive/2009/01/04/71110.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>简单的属性结构设计</title><link>http://www.cppblog.com/Fox/archive/2008/12/28/70542.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Sat, 27 Dec 2008 18:44:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/12/28/70542.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/70542.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/12/28/70542.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/70542.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/70542.html</trackback:ping><description><![CDATA[<p>本文最早发布于<a href="http://www.yulefox.com/index.php/20081228/simple-attribute-design.html/" target="_blank">我的个人主页</a></p> <p>一般的RPG游戏中，玩家角色、NPC、物品、场景等一般都具有为数众多的各种属性，使用C++编码时，很容易考虑设计成为大量的成员变量和相应的存取函数：</p><code> <p>class CObject<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; long GetAttrA(void) const { return m_lAttrA; }<br>&nbsp;&nbsp;&nbsp; void SetAttrA(long lVal) { m_lAttrA = lVal; }<br>&nbsp;&nbsp;&nbsp; long GetAttrB(void) const { return m_lAttrB; }<br>&nbsp;&nbsp;&nbsp; void SetAttrB(long lVal) { m_lAttrB = lVal; }<br>&nbsp;&nbsp;&nbsp; ...<br>&nbsp;&nbsp;&nbsp; long GetAttrN(void) const { return m_lAttrN; }<br>&nbsp;&nbsp;&nbsp; void SetAttrN(long lVal) { m_lAttrN = lVal; }  <p>private:<br>&nbsp;&nbsp;&nbsp; long m_lAttrA;<br>&nbsp;&nbsp;&nbsp; long m_lAttrB;<br>&nbsp;&nbsp;&nbsp; ...<br>&nbsp;&nbsp;&nbsp; long m_lAttrN;<br>};</p></code> <p>乍一看，非常清晰明了。在一个稍显复杂的项目中，想记住、甚至找到每一个属性是非常难的，况且除了属性，还有大量的逻辑处理，甚至是不同项目间的数据交互，比如将属性的数据库存取。这么做的缺点大致有这么几点：</p> <p>1. 属性没有明确分门别类，尤其在多人协作、多模块编写时，往往上面一批、下面一批，甚至有重复属性、废弃属性，难于管理和把握；</p> <p>2. 对于数据库存取，需要写单独的存取接口，而且一旦属性有增减、修改，存取接口要随之修改；</p> <p>3. 通过接口函数进行简单的属性存取面临大量的堆栈保存，即使使用内联或宏定义，也是治标不治本。</p> <p>针对上述问题，我的思路也比较简单：对<strong>基本类型</strong>数据进行二次封装。</p><code> <p>struct tagDBAttrs<br>{<br>&nbsp;&nbsp;&nbsp; long lA;<br>&nbsp;&nbsp;&nbsp; long lB;<br>&nbsp;&nbsp;&nbsp; ...<br>&nbsp;&nbsp;&nbsp; long lN;<br>};  <p>class CObject<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; const tagDBAttrs&amp; GetDBAttrs(void) const { return m_DBAttrs; }<br>&nbsp;&nbsp;&nbsp; void SetDBAttrs(const tagDBAttrs&amp; rDBAttrs)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memcpy(&amp;m_DBAttrs, rDBAttrs, sizeof(m_DBAttrs));<br>&nbsp;&nbsp;&nbsp; }  <p>private:<br>&nbsp;&nbsp;&nbsp; tagDBAttrs&nbsp;&nbsp;&nbsp; m_DBAttrs;<br>&nbsp;&nbsp;&nbsp; string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_strA;<br>&nbsp;&nbsp;&nbsp; CObject*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_pObjB;<br>&nbsp;&nbsp;&nbsp; CShape*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_pShapeC;<br>&nbsp;&nbsp;&nbsp; ...<br>};</code>&nbsp;</p> <p>之所以提到基本类型数据，主要缘于基本类型构成的结构可以通过<code>sizeof</code>运算符直接确定，而像类对象等组合类型，其深拷贝、赋值、操作及赋值等逻辑则较为复杂，一般无法统一处理。</p> <p>以上面的<code>tagDBAttrs</code>为例，对于基本类型数据处理具有非常大的优势，尤其在数据整体存取时，此外，增减基本类型属性也比较简单，而且不需要重写<code>Get/Set</code>接口，同时方便了对属性的分门别类处理。</p> <hr>  <p>此处顺便谈谈关于开发中的一些杂的体会。</p> <p>对于工作不久的同学而言，拿到一个任务有可能出现以下两种情况：</p> <p>1. 以快速开发为重，前期进展较快，在小型模块开发中顺风顺水，但在面对复杂任务时，因为对前期设计重视不足，后期会不断调整代码，甚至在基本功能开发结束后，因为逻辑架构问题，导致bug隐患较多较深，容易陷入泥沼，痛苦挣扎；</p> <p>2. 随时随处追求代码结构的优美和执行效率的优化，精益求精，往往在前期设计上花费过多的心思，以达到较合理的逻辑结构，甚至拖延整个项目的开发进度，这种同学一般说来，代码质量较高，后期bug较少。</p> <p>其实，上面说的就是我自己，我刚开始工作的时候，上面给我一个编写独立工具的任务，当时急于表现，缺乏项目实战经验，为编码而编码，逻辑结构不注重扩展性，设计不合理，在进行到后期时，面对出现的新需求无法应对，导致最后推到重来。</p> <p>后来，慢慢接受了注重前期设计的观念，更因为自己的完美情结和代码洁癖，不仅经常调整自己编码中不优美的片段，甚至越俎代庖去修改其他同事的代码，追求处处的高效，耗费大量时间精力，难以自拔。</p> <p>在任何一个项目中，都有轻重主次之分，也就是所谓的『<strong>8020原则</strong>』，关于『<strong>8020原则</strong>』怎么理解都行，我的理解就是，每个项目中的效率瓶颈是20%的核心代码，80%的时间和工作重心应该放到这20%的核心代码上。放到一个小的模块中也是这样，应该确定工作重心，在开发进度的限制下，对核心代码精益求精，对非效率瓶颈可以适当减少侧重。</p> <p>对于新人，最难的就是从整体的高度确定20%的工作重心，这主要依赖于自身素质的提高和开发经验的积累。而对需求深入细致的分析和对逻辑精益求精的设计本身可以训练一个人分析问题、解决问题的能力。</p> <p>总结一下的话，也正是我们项目组历来所倡导和坚持的：</p> <p>1. 精益求精；</p>2. 细节决定成败，态度制约能力。<img src ="http://www.cppblog.com/Fox/aggbug/70542.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-12-28 02:44 <a href="http://www.cppblog.com/Fox/archive/2008/12/28/70542.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式（三）&amp;mdash;&amp;mdash;Singleton</title><link>http://www.cppblog.com/Fox/archive/2008/11/19/67339.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Wed, 19 Nov 2008 15:37:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/11/19/67339.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/67339.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/11/19/67339.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/67339.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/67339.html</trackback:ping><description><![CDATA[<p>不知道Singleton算不算用的最多的，平时用的时候，往往都是直接敲下面一段：</p><code> <p>&#8230;&#8230;</p> <p>不是不想改，就是懒，敲多了已经不觉得这么写多浪费时间了，按大家的说法，这样写至少有这么几个缺点：</p> <p>1. 必须在程序结束前手动释放，这不仅是RP问题，如果你借了内存不主动还，说明你RP差，但被别人搞丢了（宕机）导致你还不上，说明别人RP差？所以，这还是个问题；</p> <p>2. 线程同步问题，如果Singleton实例跨线程使用，上例不安全，在Initial和Release时加锁可以解决；</p> <p>3. 最大的问题：不能重用。</p> <p><a href="http://www.yulefox.com/index.php/20081119/design-patterns-03.html/" target="_blank">阅读全文</a></p></code><img src ="http://www.cppblog.com/Fox/aggbug/67339.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-11-19 23:37 <a href="http://www.cppblog.com/Fox/archive/2008/11/19/67339.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式（二）&amp;mdash;&amp;mdash;State</title><link>http://www.cppblog.com/Fox/archive/2008/11/19/67251.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Tue, 18 Nov 2008 16:57:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/11/19/67251.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/67251.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/11/19/67251.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/67251.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/67251.html</trackback:ping><description><![CDATA[<p><strong>State模式</strong>对应到C++的<strong>多态</strong>特性。</p> <p><strong>State模式</strong>适用较广，这儿给出比较常见易懂的三种情况：</p> <p>1. 当怪物在面对不同职业和特性的玩家时对应不同的AI处理和技能释放：</p><code> <p>CSkill* pAttackSkill;</p> <p>if( pPlayer-&gt;MagicImmune() ) pAttackSkill = SomePhysicalAttackSkill;</p> <p>else if( pPlayer-&gt;PhysicalImmune() ) pAttackSkill = SomeMagicAttackSkill;</p> <p>...</p> <p>pAttackSkill-&gt;Begin();</p> <p>...</p></code> <p>或者使用分支结构：</p><code> <p>CSkill* pAttackSkill;</p> <p>switch( pPlayer-&gt;GetOccupation() ) </p> <p>{</p> <p>&nbsp; case WARRIOR: pAttackSkill = SomeLongRangeSkill; break;</p> <p>&nbsp; case MAGICIAN: pAttackSkill = SomeForceSkill; break;</p> <p>&nbsp; case NIMROD: pAttackSkill = SomeMagicSkill; break;</p> <p>...</p> <p>}</p> <p>pAttackSkill-&gt;Begin();</p> <p>...</p></code> <p><a href="http://www.yulefox.com/index.php/20081119/design-patterns-02.html/" target="_blank">阅读全文</a></p><img src ="http://www.cppblog.com/Fox/aggbug/67251.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-11-19 00:57 <a href="http://www.cppblog.com/Fox/archive/2008/11/19/67251.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>感谢大家的支持</title><link>http://www.cppblog.com/Fox/archive/2008/11/10/66496.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Mon, 10 Nov 2008 03:17:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/11/10/66496.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/66496.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/11/10/66496.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/66496.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/66496.html</trackback:ping><description><![CDATA[<p>因站点迁移。请订阅本博的朋友将RSS修改为<a href="http://www.yulefox.com/?feed=rss2">http://www.yulefox.com/?feed=rss2</a><br><br>个人主页地址：<a href="http://www.yulefox.com">http://www.yulefox.com</a></p><img src ="http://www.cppblog.com/Fox/aggbug/66496.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-11-10 11:17 <a href="http://www.cppblog.com/Fox/archive/2008/11/10/66496.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>可以带狗但不能带人的Google</title><link>http://www.cppblog.com/Fox/archive/2008/11/10/66465.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Sun, 09 Nov 2008 16:13:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/11/10/66465.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/66465.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/11/10/66465.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/66465.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/66465.html</trackback:ping><description><![CDATA[<p>之所以要写这个东西，是因为由最近发生的<a title="腾讯诉15员工竞业限制案" href="http://www.yulefox.com/index.php/20081108/tencent-indict-employees.html/" target="_blank">腾讯竞业禁止案</a>发散思维了。借机反思一下<strong>员工对企业认同的源与流</strong>。  <p>之所以要写Google，Google是我的梦，正像我当初在一份简历中写道的：  <p><strong>Game is my interest, so I like developing my game; Google is my life, so I love enjoying my life.</strong>  <p>我的工作、学习、生活离不开Google：<strong>My indispensable tools: Gmail, G.cn, Code, iGoogle, Picasa, Reader, Talk, Notebook, Map, Calendar, Documents, Google Pinyin, Chrome, etc.</strong>  <p>不煽情了，坊间流传的最多的就是富有<strong>传奇色彩</strong>的<strong>Google的工作环境和待遇</strong>，下图可以说明很多问题了： <p><a title="可以带狗但不能带人的Google" href="http://www.yulefox.com/index.php/20081110/google-with-dog.html/" target="_blank">阅读全文</a>……</p><img src ="http://www.cppblog.com/Fox/aggbug/66465.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-11-10 00:13 <a href="http://www.cppblog.com/Fox/archive/2008/11/10/66465.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>终论Fibonacci数</title><link>http://www.cppblog.com/Fox/archive/2008/11/06/66071.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Wed, 05 Nov 2008 16:34:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/11/06/66071.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/66071.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/11/06/66071.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/66071.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/66071.html</trackback:ping><description><![CDATA[<p>现在每天的工作主要是为了满足项目需求和进度而不停的思考、敲键盘。有时候也确实需要抽点时间来思考思考那些看上去用不到的一些东西，又想起了<strong>Fibonacci数</strong>。</p> <p>之前曾经三次写过<strong>Fibonacci数</strong>：2007年4月的<a title="我的Fibonacci数列" href="http://www.yulefox.com/index.php/20070420/my-fibonacci-serial.html/" target="_blank">我的Fibonacci数列</a>，2007年12月的<a title="也说说级数求和(1+2+3&hellip;N)和其他" href="http://www.yulefox.com/index.php/20071221/simple-series-sum.html/" target="_blank">也说说级数求和(1+2+3…N)和其他</a>，2008年5月的<a href="http://www.yulefox.com/index.php/20080507/introduction-of-dynamic-programming.html/">动态规划算法</a>，但给出的都不是非常优的算法。</p> <p>上次回去把同学借的《编程之美》偷过来还没怎么看，晚上翻了一下，看到有讲<strong>Fibonacci数</strong>，想起来<a title="Donald E.Knuth" href="http://en.wikipedia.org/wiki/Donald_knuth" target="_blank" rel="tag">Knuth</a>的The Art of Computer Programming Vol.1也讲过，觉得有必要对<strong>Fibonacci数</strong>做个了断。</p> <p>诚如<a title="Donald E.Knuth" href="http://en.wikipedia.org/wiki/Donald_knuth" target="_blank" rel="tag">Knuth</a>在The Art of Computer Programming Vol.1所述，<a title="Fibonacci" href="http://en.wikipedia.org/wiki/Fibonacci" target="_blank" rel="tag">Fibonacci</a>是中世纪以来欧洲最伟大的数学家，他关于al-Khwarizmi的研究催生了算法（algorithm）一词。</p> <p><a href="http://www.yulefox.com/index.php/20081105/fibonacci-sequence-summarize.html/" target="_blank">阅读全文</a></p> <p><strong>看到这些，我又激动了，数学之美，不正是美在这些地方吗？我们不是要做数学家，但这并不妨碍我们站在门口向里张望……</strong></p><img src ="http://www.cppblog.com/Fox/aggbug/66071.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-11-06 00:34 <a href="http://www.cppblog.com/Fox/archive/2008/11/06/66071.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WSAEventSelect剖析</title><link>http://www.cppblog.com/Fox/archive/2008/10/27/65263.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Mon, 27 Oct 2008 15:25:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/10/27/65263.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/65263.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/10/27/65263.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/65263.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/65263.html</trackback:ping><description><![CDATA[<p>本文同时发布在<a title="http://www.yulefox.com" href="http://www.yulefox.com" target="_blank" rel="tag">http://www.yulefox.com</a>和<a title="http://www.cppblog.com/fox" href="http://www.cppblog.com/fox" target="_blank" rel="tag">http://www.cppblog.com/fox</a>。 <p>近来在Windows下用WSAEventSelect时，碰到一个棘手的问题，当然现在已经解决了。  <p><strong>问题描述：</strong>  <p>一个Server，一个ClientA，一个ClientB，Server用WSAEventSelect模型监听（只有监听，没有读写），ClientA在连接Server后，ClientA对应的EventA被触发，Server的WSAWaitForMultipleEvents等待到EventA，ClientB连接Server时，TCP三次握手成功，ClientB与Server的TCP状态被置为ESTABLISHED，然而Server的WSAWaitForMultipleEvents没有等待到EventB被触发。  <p>用netstat看了一下，ClientB与Server的状态是ESTABLISHED，此时如果ClientB退出，由于Server无法正常Close该连接，因此Server的状态不是TIME_WAIT而是CLOSE_WAIT（持续2小时），Client的状态是FIN_WAIT_2（持续10分钟）。  <p>我尝试将ClientA主动关闭后再次连接Server，Server的WSAWaitForMultipleEvents在wait到EventA之后，EventB此时也被触发。  <p>开始一直以为问题的根源在于WSAEventSelect的使用上，毕竟，之前没有系统写过类似的代码，难免怀疑到事件模型的使用上。多方查阅资料，最后还是没有发现类似问题的解决方案。  <p>又跟了一上午之后，Kevin开始怀疑是多线程使用的问题，我看了一下，的确没有对event的多线程操作进行处理，但因为在另一个应用中，使用了同样的模块，却没有该问题。最后考虑必要性时还是放弃了加临界资源，无视多线程同步问题。Kevin本来劝我换个模型，但我固执的认为要做就把这事儿做好。因为下午还要回学校一趟，就想尽快搞定，毕竟因为这一块已经把Kevin的进度拖了一周了，心下还是过意不去，而且隐约感觉到离问题的解决越来越近了。  <p><strong>问题分析：</strong>  <p>在对着WSAWaitForMultipleEvents思考了半天之后，忽然开窍了，如果ThreadA在WSAWaitForMultipleEvents时，只有一个EventA被WSAEventSelect并set到signaled状态，则该EventA会被wait成功，ThreadA处理EventA之后继续阻塞在WSAWaitForMultipleEvents。此时，ThreadB通过WSAEventSelect将EventB初始化为nonsignaled状态，之后即使EventB被set为signaled状态，但ThreadA的WSAWaitForMultipleEvents因为处于阻塞状态，不可能刷新事件集，也就不可能wait到EventB，最终导致了ClientB的请求无法被响应。如果EventA被触发则会被ThreadA等待到，WSAWaitForMultipleEvents返回后再次进入时事件集已经被刷新，EventB被wait到也就不难理解了。  <p><strong>问题解决：</strong>  <p>说到底是因为当ThreadA阻塞在WSAWaitForMultipleEvents处之时，事件集的变更无法立即得到体现。如果允许上层应用随时create或close一些event，则WSAWaitForMultipleEvents就不应该无限阻塞下去。  <p>因此最后的一个解决方法就是让WSAWaitForMultipleEvents超时返回并Sleep一段时间，当WSAWaitForMultipleEvents再次进入时事件集得以更新。  <p>想了一下，另一个应用中之所以没出现该问题也只是个巧合，因为该应用中ThreadB的两次WSAEventSelect间隔很短，在ThreadA获得时间片之前已经确定了事件集。  <p>说白了这也不是一个什么大问题，甚至谈不上任何难度，但是因为之前对WSAEventSelect没有一个清晰的概念，因此在发现和分析问题上花费了大量时间，加上在VS2005调试过程中，有个别文件更新时没有被重新编译，也耗费了很多无谓的时间，以至于我们都在考虑是不是要放弃IDE，因为我们确实太依赖IDE了，有些TX为了稳妥，每次都是“重新生成整个解决方案”，如果一个解决方案有几千个文件、几十万行的代码，估计重编一次也要花个几分钟吧。  <p><strong>总结：</strong>  <ol> <li>netstat观察的网络连接处于ESTABLISHED状态并不意味着逻辑连接被accept，只是表明客户端connect的TCP物理连接（三次握手）被服务器端ack，如果服务器没有accept到该连接，证明网络模块代码有问题；  <li>多线程怎么都是个问题，线程同步尽量避免，毕竟，用Kevin的话来说，加锁是丑陋的。但在涉及到同步问题时，还是权衡一下，我这儿之所以最后没有加临界区，是因为事件主要是在ThreadA中处理，ThreadB中只有create操作，而且ThreadA对事件集的刷新要求不是那么严格，也就不考虑加临界区了；  <li>如果能力和条件允许的话，放弃IDE吧，IDE的确不是个好东西，我主要是指在编译链接的时候，如果作为编辑器说不定还会好用:)。 </li></ol> <hr width="50%">  <p>个人网站<a title="http://www.yulefox.com" href="http://www.yulefox.com" target="_blank" rel="tag">http://www.yulefox.com</a>用的主机最近从据说要黑屏的Windows换成了Debian，还在调整，估计明天能弄好，内容肯定比Cppblog杂的多，谈点技术的还是会同步更新到<a title="http://www.cppblog.com/fox" href="http://www.cppblog.com/fox" target="_blank" rel="tag">http://www.cppblog.com/fox</a>。</p><img src ="http://www.cppblog.com/Fox/aggbug/65263.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-10-27 23:25 <a href="http://www.cppblog.com/Fox/archive/2008/10/27/65263.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>支持成员函数指针的消息映射机制的简单实现</title><link>http://www.cppblog.com/Fox/archive/2008/10/10/63625.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Fri, 10 Oct 2008 02:20:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/10/10/63625.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/63625.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/10/10/63625.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/63625.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/63625.html</trackback:ping><description><![CDATA[<p>作者：Fox</p> <p>本文同时发布在<a href="http://www.yulefox.com">http://www.yulefox.com</a>和<a href="http://www.cppblog.com/fox">http://www.cppblog.com/fox</a>。</p> <p>十天之前，在CPPBLOG上写了一篇<a title="消息映射机制的简单实现" href="http://www.cppblog.com/Fox/archive/2008/09/29/63056.html" target="_blank" rel="tag">消息映射机制的简单实现</a>，有同学提到该实现不支持成员函数。这个问题我也考虑到了，既然被提出来，不妨把实现提供出来。</p> <p>需要说明的是，我本身对template比较不感冒，不过<a title="Kevin Lynx" href="http://www.cppblog.com/kevinlynx/archive/2008/03/17/44678.html" target="_blank" rel="tag">Kevin Lynx</a>对template感冒，而且写过关于成员函数指针的问题，想了很久，如果支持成员函数指针，不用模板是不行了。</p> <p>此处对成员函数的支持还不涉及对函数参数的泛化，因为我这个消息映射暂时不需要参数泛化，下面的代码应该不需要过多的解释了。</p><code> <p>#define REG_MSG_FUNC(nMsgType, MsgFunc) \ <br>&nbsp;&nbsp;&nbsp; CMsgRegister::RegisterCallFunc(nMsgType, MsgFunc); </p> <p>#define REG_MSG_MEM_FUNC(nMsgType, Obj, MsgFunc) \ <br>&nbsp;&nbsp;&nbsp; CMsgRegister::RegisterCallFunc(nMsgType, Obj, MsgFunc); </p> <p>class CBaseMessage; </p> <p>class CHandler <br>{ <br>public: <br>&nbsp;&nbsp;&nbsp; virtual int operator()(CBaseMessage* pMsg) = 0; <br>}; </p> <p>template&lt;typename FuncType&gt; <br>class CDefHandler : public CHandler <br>{ <br>public: <br>&nbsp;&nbsp;&nbsp; CDefHandler(){} <br>&nbsp;&nbsp;&nbsp; CDefHandler(FuncType &amp;Func) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : m_Func(Func) <br>&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp; } </p> <p>&nbsp;&nbsp;&nbsp; virtual int operator()(CBaseMessage* pMsg) <br>&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return m_Func(pMsg); <br>&nbsp;&nbsp;&nbsp; } </p> <p>protected: <br>&nbsp;&nbsp;&nbsp; FuncType&nbsp;&nbsp;&nbsp; m_Func; <br>}; </p> <p>template&lt;typename ObjType, typename FuncType&gt; <br>class CMemHandler : public CHandler <br>{ <br>public: <br>&nbsp;&nbsp;&nbsp; CMemHandler(){} <br>&nbsp;&nbsp;&nbsp; CMemHandler(ObjType* pObj, FuncType Func) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : m_pObj(pObj) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , m_Func(Func) <br>&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp; } </p> <p>&nbsp;&nbsp;&nbsp; virtual int operator()(CBaseMessage* pMsg) <br>&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (m_pObj-&gt;*m_Func)(pMsg); <br>&nbsp;&nbsp;&nbsp; } </p> <p>protected: <br>&nbsp;&nbsp;&nbsp; FuncType&nbsp;&nbsp;&nbsp; m_Func; <br>&nbsp;&nbsp;&nbsp; ObjType*&nbsp;&nbsp;&nbsp; m_pObj; <br>}; </p> <p>class CFunction <br>{ <br>public: <br>&nbsp;&nbsp;&nbsp; CFunction() <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : m_pHandler(NULL) <br>&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp; } </p> <p>&nbsp;&nbsp;&nbsp; // 封装(C函数或静态成员函数) <br>&nbsp;&nbsp;&nbsp; template&lt;typename FuncType&gt; <br>&nbsp;&nbsp;&nbsp; CFunction( FuncType &amp;Func ) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : m_pHandler(new CDefHandler&lt;FuncType&gt;(Func)) <br>&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp; } </p> <p>&nbsp;&nbsp;&nbsp; // 封装(非静态成员函数) <br>&nbsp;&nbsp;&nbsp; template&lt;typename ObjType, typename FuncType&gt; <br>&nbsp;&nbsp;&nbsp; CFunction( ObjType* pObj, FuncType Func ) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : m_pHandler(new CMemHandler&lt;ObjType, FuncType&gt;(pObj, Func)) <br>&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp; } </p> <p>&nbsp;&nbsp;&nbsp; virtual ~CFunction() <br>&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DELETE_SAFE(m_pHandler); <br>&nbsp;&nbsp;&nbsp; } </p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 函数调用 <br>&nbsp;&nbsp;&nbsp; int operator()(CBaseMessage* pMsg) <br>&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (*m_pHandler)(pMsg); <br>&nbsp;&nbsp;&nbsp; } </p> <p>private: <br>&nbsp;&nbsp;&nbsp; CHandler&nbsp;&nbsp;&nbsp; *m_pHandler; <br>}; </p> <p>typedef std::map&lt;int, CFunction*&gt; MSG_MAP; <br>typedef MSG_MAP::iterator MSG_ITR; </p> <p>class CMsgRegister <br>{ <br>public: <br>&nbsp;&nbsp;&nbsp; // 注册消息函数(C函数或静态成员函数) <br>&nbsp;&nbsp;&nbsp; template &lt;typename FuncType&gt; <br>&nbsp;&nbsp;&nbsp; inline static void RegisterCallFunc(int nMsgType, FuncType &amp;Func) <br>&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CFunction *func = new CFunction(Func); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s_MsgMap[nMsgType] = func; <br>&nbsp;&nbsp;&nbsp; } </p> <p>&nbsp;&nbsp;&nbsp; // 注册消息函数(非静态成员函数) <br>&nbsp;&nbsp;&nbsp; template &lt;typename ObjType, typename FuncType&gt; <br>&nbsp;&nbsp;&nbsp; inline static void RegisterCallFunc(int nMsgType, ObjType* pObj, FuncType Func) <br>&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CFunction *func = new CFunction(pObj, Func); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s_MsgMap[nMsgType] = func; <br>&nbsp;&nbsp;&nbsp; } </p> <p>&nbsp;&nbsp;&nbsp; // 执行消息 <br>&nbsp;&nbsp;&nbsp; inline static void RunCallFunc(int nMsgType, CBaseMessage* pMsg) <br>&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MSG_ITR itr = s_MsgMap.find(nMsgType); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( s_MsgMap.end() != itr ) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*itr-&gt;second)(pMsg); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br>&nbsp;&nbsp;&nbsp; } </p> <p>&nbsp;&nbsp;&nbsp; static void ReleaseMsgMap()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 释放消息映射表 <br>&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MSG_ITR itr = s_MsgMap.begin(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while( itr != s_MsgMap.end() ) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DELETE_SAFE(itr-&gt;second); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; itr = s_MsgMap.erase(itr); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br>&nbsp;&nbsp;&nbsp; } </p> <p>protected: <br>&nbsp;&nbsp;&nbsp; static MSG_MAP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s_MsgMap;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 消息映射表 <br>};</p></code> <p>不可否认，模板给了你更大的想象空间，很多东西，还是不要一味排斥的好:)。</p><img src ="http://www.cppblog.com/Fox/aggbug/63625.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-10-10 10:20 <a href="http://www.cppblog.com/Fox/archive/2008/10/10/63625.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>