﻿<?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++博客-白云哥-随笔分类-Others</title><link>http://www.cppblog.com/helloqinglan/category/14448.html</link><description>身披半件长工衣，怀揣一颗地主心</description><language>zh-cn</language><lastBuildDate>Mon, 16 Aug 2010 20:46:59 GMT</lastBuildDate><pubDate>Mon, 16 Aug 2010 20:46:59 GMT</pubDate><ttl>60</ttl><item><title>C++中遍历容器对象时需要注意的问题</title><link>http://www.cppblog.com/helloqinglan/archive/2010/08/12/123254.html</link><dc:creator>白云哥</dc:creator><author>白云哥</author><pubDate>Thu, 12 Aug 2010 15:02:00 GMT</pubDate><guid>http://www.cppblog.com/helloqinglan/archive/2010/08/12/123254.html</guid><wfw:comment>http://www.cppblog.com/helloqinglan/comments/123254.html</wfw:comment><comments>http://www.cppblog.com/helloqinglan/archive/2010/08/12/123254.html#Feedback</comments><slash:comments>13</slash:comments><wfw:commentRss>http://www.cppblog.com/helloqinglan/comments/commentRss/123254.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/helloqinglan/services/trackbacks/123254.html</trackback:ping><description><![CDATA[<p><font size="4">假设有这样一个管理对象的窗口 ActorManager，其实现大概为</font></p><pre class="brush: cpp; ruler: true; collapse: true;">class Actor;<br>class ActorManager<br>{<br>public:<br>    void update()<br>    {<br>        for (actors_t::const_iterator itr = m_actors.begin(); itr != m_actors.end(); ++itr)<br>        {<br>            Actir* actor = itr-&gt;second;<br>            actor-&gt;update();<br>        }<br>    }<br><br>    void add(Actor* actor)<br>    {<br>        m_actors[actor-&gt;get_id()] = actor;<br>    }<br><br>    void remove(Actor* actor)<br>    {<br>        m_actors.erase(actor-&gt;get_id());<br>    }<br><br>private:<br>    typedef std::map&lt;int, Actor*&gt; actors_t;<br>    actors_t m_actors;<br>};</pre>
<p><font color="#000000" face="Courier New"></font>&nbsp;</p>
<p><font size="4">而Actor类的实现是这样：</font></p><pre class="brush: cpp; ruler: true; collapse: true;">class Actor<br>{<br>public:<br>    void update()<br>    {<br>        // ...<br><br>    }</pre>
<p><font size="4">有一天，在给Actor添加逻辑的时候，update函数变成了这样</font></p><pre class="brush: cpp; ruler: true; collapse: true;">void update()<br>{<br>    // ...<br><br>    update_buff_effect();<br><br>    // ...<br>}</pre>
<p>&nbsp;</p>
<p><font size="4">再往下</font></p>
<p>&nbsp;</p><pre class="brush: cpp; ruler: true; collapse: true;">class Actor<br>{<br>       // ...<br><br>private:<br>    void update_buff_effect()<br>    {<br>        // ...<br><br>        apply_hp(-100);<br>        if (get_hp() &lt;= 0)<br>        {<br>            die();<br>            return;<br>        }<br><br>        // ...<br>    }</pre>
<p>&nbsp;</p>
<p><font size="4">然后&#8230;&#8230;</font></p>
<p>&nbsp;</p><pre class="brush: cpp; ruler: true; collapse: true;">private:<br>    void die()<br>    {<br>        // ...<br><br>        ActorManager::getInstance().remove(this);<br><br>        // ...<br>    }</pre><pre class="brush: cpp; ruler: true; collapse: true;"><font size="4">在写下ActorManager的时候并没有想到会在update循环里删除对象，而实际上却有几次遇到类似的问题。</font></pre><pre class="brush: cpp; ruler: true; collapse: true;"><font size="4">有些问题没有这么明显，但也都是出在遍历容器对象的过程中，某个执行函数删除了窗口里的对象，从而导致迭代器失效。</font></pre><pre class="brush: cpp; ruler: true; collapse: true;"><font size="4"></font>&nbsp;</pre><pre class="brush: cpp; ruler: true; collapse: true;"><font size="4">修改的方法很简单，给ActorManager添加一个待删除对象列表</font></pre><pre class="brush: cpp; ruler: true; collapse: true;"><font size="4">在remove方法中并不真正删除对象，而是等到update中循环结束后再删除对象。</font></pre><pre class="brush: cpp; ruler: true; collapse: true;"><font size="4">代码看起来会是这样：</font></pre><pre class="brush: cpp; ruler: true; collapse: true;"><font size="4"></font></pre><pre class="brush: cpp; ruler: true; collapse: true;">class Actor;<br>class ActorManager<br>{<br>public:<br>    void update()<br>    {<br>        m_is_looping = true;<br>        for (actors_t::const_iterator itr = m_actors.begin(); itr != m_actors.end(); ++itr)<br>        {<br>            Actir* actor = itr-&gt;second;<br>            actor-&gt;update();<br>        }<br>        m_is_looping = false;<br><br>        if (!m_removed_actors.empty())<br>        {<br>            for (removed_actors_t::const_iterator itr = m_removed_actors.begin();<br>                itr != m_removed_actors.end(); ++itr)<br>            {<br>                Actor* actor = *itr;<br>                m_actors.erase(actor-&gt;get_id());<br>            }<br>            m_removed_actors.clear();<br>        }<br>    }<br><br>    void add(Actor* actor)<br>    {<br>        m_actors[actor-&gt;get_id()] = actor;<br>    }<br><br>    void remove(Actor* actor)<br>    {<br>        if (!m_is_looping)<br>            m_actors.erase(actor-&gt;get_id());<br>        else<br>            m_removed_actors.push_back(actor);<br>    }<br><br>private:<br>    typedef std::map&lt;int, Actor*&gt; actors_t;<br>    actors_t m_actors;<br><br>    typedef std::vector&lt;Actor*&gt; removed_actors_t;<br>    removed_actors_t m_removed_actors;<br>    bool m_is_looping;<br>};</pre>
<p>&nbsp;</p>
<p><font color="#000000" size="4" face="Courier New">没有给add也加保护的原因是，不会在update函数内向ActorManager添加新对象。</font></p>
<p><font color="#000000" size="4" face="Courier New">当然，有可能在其他地方会有这样的需求，同样也做类似的保护即可。</font></p>
<p><font color="#000000" size="4" face="Courier New"></font>&nbsp;</p>
<p><font color="#000000" size="4" face="Courier New"></font>&nbsp;</p>
<p><font color="#000000" size="4" face="Courier New">问题虽然不大，但是几次碰到类似的错误了。记录之，并强制要求自己，</font></p>
<p><font color="#000000" size="4" face="Courier New">在遇到会对容器内的对象做for&#8230;处理时，一定要谨慎的检查一下remove接口。</font></p><img src ="http://www.cppblog.com/helloqinglan/aggbug/123254.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/helloqinglan/" target="_blank">白云哥</a> 2010-08-12 23:02 <a href="http://www.cppblog.com/helloqinglan/archive/2010/08/12/123254.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Framework Design Guidelines读书笔记</title><link>http://www.cppblog.com/helloqinglan/archive/2010/08/07/122491.html</link><dc:creator>白云哥</dc:creator><author>白云哥</author><pubDate>Fri, 06 Aug 2010 16:19:00 GMT</pubDate><guid>http://www.cppblog.com/helloqinglan/archive/2010/08/07/122491.html</guid><wfw:comment>http://www.cppblog.com/helloqinglan/comments/122491.html</wfw:comment><comments>http://www.cppblog.com/helloqinglan/archive/2010/08/07/122491.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/helloqinglan/comments/commentRss/122491.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/helloqinglan/services/trackbacks/122491.html</trackback:ping><description><![CDATA[<p><font size="4">这本书虽然是讲述.net框架设计的一些规范，不过仍然有一些通用的设计准则可以参考</font></p> <p><font size="4"></font>&nbsp;</p> <p><font size="4">命名规范：</font></p> <p><font size="4">这些只有在用于公开暴露给外界的API时才是必需的</font></p> <p><font size="4"></font>&nbsp;</p> <p><font size="4">标识符大小写规则：</font></p> <p><font size="4">1.要把PascalCasing用于由多个单词构成的名字空间，类型以及成员的名字</font></p> <p><font size="4">2.要把camelCasing用于参数的名字</font></p> <p><font size="4">3.不要把闭合形式的复合词中每个单词的首字母大写，比如 callback, endpoint 等等，可以查阅英语词典来确定复合词是不是闭合的</font></p> <p><font size="4">4.不要使用匈牙利命名法。原因有几点，一是发明它的ms公司都已经明确要求在新的库在不要使用这种命名法，二是变量名前加类型标识符是个很不好的习惯，在开发过程中有可能会随时修改这些变量的类型定义，三是新的编辑器中不需要用m_前缀来确定其类型，不过对于内部实现的变量来说，用一个前缀也许会让变量的查找更方便，比如用一个_前缀</font></p> <p><font size="4">5.不要使用未被广泛接受的首字母缩写词，如何确定某个缩写词是否众所周知有个好方法，到google上搜索一下，如果前几条都是你所期望的内容，那么它就是众所周知的了</font></p> <p><font size="4"></font>&nbsp;</p> <p><font size="4">关于命名：</font></p> <p><font size="4">1.要用名词或名词短语来给类和结构体命名，使用PascalCasing的大小写风格，类名字不要加 C，但是接口前需要加 I，这是个特例</font></p> <p><font size="4">2.用形容词短语来给接口命名，在少数情况下也可以使用名词或名词短语</font></p> <p><font size="4">3.考虑在派生类的末尾使用基类的名字，比如 class FileStream : public Stream</font></p> <p><font size="4">4.用动词或动词短语来命名方法，比如 int CompareTo();</font></p> <p><font size="4">5.要用肯定性的短语(CanSeek而不是CantSeek)来命名布尔属性，可以加Is,Can,Has等前缀，要确保使用时的测试语句读起来通顺，比如</font></p> <p><font size="4">if (collection.Contains(item)) 就比 if (collection.IsContained(item)) 要通顺得多</font></p> <p><font size="4">此外，要优先选择主动语态而不是被动语态，比如</font></p> <p><font size="4">if (stream.CanSeek()) 就比 if (steam.IsSeekable()) 要强得多</font></p> <p><font size="4">6.要用现在时和过去时来赋予事件名以之前和之后的概念，不要用Before或After这样的前后缀，比如 Closing, Closed而不是AfterClose</font></p> <p><font size="4"></font>&nbsp;</p> <p><font size="4">使用规范：</font></p> <p><font size="4">1.优先使用集合，避免使用数组</font></p> <p><font size="4">2.考虑使用不规则数组，而不要使用多维数组，也就是优先使用int [][] jagedArray这样的数组，避免使用 int [,] multiDimArray这样的类型</font></p> <p><font size="4">3.要用最泛的类型来作为参数类型，大多数以集合为参数的成员都使用IEnumerable&lt;T&gt; 接口</font></p> <p><font size="4"></font></p><img src ="http://www.cppblog.com/helloqinglan/aggbug/122491.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/helloqinglan/" target="_blank">白云哥</a> 2010-08-07 00:19 <a href="http://www.cppblog.com/helloqinglan/archive/2010/08/07/122491.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>