??xml version="1.0" encoding="utf-8" standalone="yes"?>
class Actor;
class ActorManager
{
public:
void update()
{
for (actors_t::const_iterator itr = m_actors.begin(); itr != m_actors.end(); ++itr)
{
Actir* actor = itr->second;
actor->update();
}
}
void add(Actor* actor)
{
m_actors[actor->get_id()] = actor;
}
void remove(Actor* actor)
{
m_actors.erase(actor->get_id());
}
private:
typedef std::map<int, Actor*> actors_t;
actors_t m_actors;
};
而Actorcȝ实现是这P
class Actor
{
public:
void update()
{
// ...
}
有一天,在给Actord逻辑的时候,update函数变成了这?/font>
void update()
{
// ...
update_buff_effect();
// ...
}
再往?/font>
class Actor
{
// ...
private:
void update_buff_effect()
{
// ...
apply_hp(-100);
if (get_hp() <= 0)
{
die();
return;
}
// ...
}
然后……
private:
void die()
{
// ...
ActorManager::getInstance().remove(this);
// ...
}
在写下ActorManager的时候ƈ没有惛_会在update循环里删除对象,而实际上却有几次遇到cM的问题?/font>
有些问题没有q么明显Q但也都是出在遍历容器对象的q程中,某个执行函数删除了窗口里的对象,从而导致P代器失效?/font>
修改的方法很单,lActorManagerd一个待删除对象列表
在removeҎ(gu)中ƈ不真正删除对象,而是{到update中@环结束后再删除对象?/font>
代码看v来会是这P
class Actor;
class ActorManager
{
public:
void update()
{
m_is_looping = true;
for (actors_t::const_iterator itr = m_actors.begin(); itr != m_actors.end(); ++itr)
{
Actir* actor = itr->second;
actor->update();
}
m_is_looping = false;
if (!m_removed_actors.empty())
{
for (removed_actors_t::const_iterator itr = m_removed_actors.begin();
itr != m_removed_actors.end(); ++itr)
{
Actor* actor = *itr;
m_actors.erase(actor->get_id());
}
m_removed_actors.clear();
}
}
void add(Actor* actor)
{
m_actors[actor->get_id()] = actor;
}
void remove(Actor* actor)
{
if (!m_is_looping)
m_actors.erase(actor->get_id());
else
m_removed_actors.push_back(actor);
}
private:
typedef std::map<int, Actor*> actors_t;
actors_t m_actors;
typedef std::vector<Actor*> removed_actors_t;
removed_actors_t m_removed_actors;
bool m_is_looping;
};
没有ladd也加保护的原因是Q不会在update函数内向ActorManagerd新对象?/font>
当然Q有可能在其他地方会有这L需求,同样也做cM的保护即可?/font>
问题虽然不大Q但是几ơ碰到类似的错误了。记录之Qƈ强制要求自己Q?/font>
在遇C对容器内的对象做for…处理Ӟ一定要谨慎的检查一下remove接口?/font>
命名规范Q?/font>
q些只有在用于公开暴露l外界的API时才是必需?/font>
标识W大写规则Q?/font>
1.要把PascalCasing用于由多个单词构成的名字I间Q类型以及成员的名字
2.要把camelCasing用于参数的名?/font>
3.不要把闭合Ş式的复合词中每个单词的首字母大写Q比?callback, endpoint {等Q可以查阅英语词典来定复合词是不是闭合?/font>
4.不要使用匈牙利命名法。原因有几点Q一是发明它的ms公司都已l明要求在新的库在不要使用q种命名法,二是变量名前加类型标识符是个很不好的习惯Q在开发过E中有可能会随时修改q些变量的类型定义,三是新的~辑器中不需要用m_前缀来确定其cdQ不q对于内部实现的变量来说Q用一个前~也许会让变量的查找更方便Q比如用一个_前缀
5.不要使用未被q泛接受的首字母~写词,如何定某个~写词是否众所周知有个好方法,到google上搜索一下,如果前几条都是你所期望的内容,那么它就是众所周知的了
关于命名Q?/font>
1.要用名词或名词短语来l类和结构体命名Q用PascalCasing的大写风格Q类名字不要?CQ但是接口前需要加 IQ这是个特例
2.用Ş容词短语来给接口命名Q在数情况下也可以使用名词或名词短?/font>
3.考虑在派生类的末用基cȝ名字Q比?class FileStream : public Stream
4.用动词或动词短语来命名方法,比如 int CompareTo();
5.要用肯定性的短语(CanSeek而不是CantSeek)来命名布?yu)属性,可以加Is,Can,Has{前~Q要保使用时的试语句读v来通顺Q比?/font>
if (collection.Contains(item)) 比 if (collection.IsContained(item)) 要通顺得多
此外Q要优先选择d语态而不是被动语态,比如
if (stream.CanSeek()) 比 if (steam.IsSeekable()) 要强得多
6.要用现在时和q去时来赋予事g名以之前和之后的概念Q不要用Before或Afterq样的前后缀Q比?Closing, Closed而不是AfterClose
使用规范Q?/font>
1.优先使用集合Q避免用数l?/font>
2.考虑使用不规则数l,而不要用多l数l,也就是优先用int [][] jagedArrayq样的数l,避免使用 int [,] multiDimArrayq样的类?/font>
3.要用最泛的cd来作为参数类型,大多C集合为参数的成员都用IEnumerable<T> 接口