C++中遍历容器对象时需要注意的问题
2010-08-12 23:02
267 查看
假设有这样一个管理对象的容器ActorManager,其实现大概为
classActor;
classActorManager
{
public:
voidupdate()
{
for(actors_t::const_iteratoritr=m_actors.begin();itr!=m_actors.end();++itr)
{
Actir*actor=itr->second;
actor->update();
}
}
voidadd(Actor*actor)
{
m_actors[actor->get_id()]=actor;
}
voidremove(Actor*actor)
{
m_actors.erase(actor->get_id());
}
private:
typedefstd::mapactors_t;
actors_tm_actors;
};
而Actor类的实现是这样:
classActor
{
public:
voidupdate()
{
//...
}
有一天,在给Actor添加逻辑的时候,update函数变成了这样
voidupdate()
{
//...
update_buff_effect();
//...
}
再往下
classActor
{
//...
private:
voidupdate_buff_effect()
{
//...
apply_hp(-100);
if(get_hp()<=0)
{
die();
return;
}
//...
}
然后……
private:
voiddie()
{
//...
ActorManager::getInstance().remove(this);
//...
}
在写下ActorManager的时候并没有想到会在update循环里删除对象,而实际上却有几次遇到类似的问题。
有些问题没有这么明显,但也都是出在遍历容器对象的过程中,某个执行函数删除了窗口里的对象,从而导致迭代器失效。
修改的方法很简单,给ActorManager添加一个待删除对象列表
在remove方法中并不真正删除对象,而是等到update中循环结束后再删除对象。
代码看起来会是这样:
classActor;
classActorManager
{
public:
voidupdate()
{
m_is_looping=true;
for(actors_t::const_iteratoritr=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_iteratoritr=m_removed_actors.begin();
itr!=m_removed_actors.end();++itr)
{
Actor*actor=*itr;
m_actors.erase(actor->get_id());
}
m_removed_actors.clear();
}
}
voidadd(Actor*actor)
{
m_actors[actor->get_id()]=actor;
}
voidremove(Actor*actor)
{
if(!m_is_looping)
m_actors.erase(actor->get_id());
else
m_removed_actors.push_back(actor);
}
private:
typedefstd::mapactors_t;
actors_tm_actors;
typedefstd::vectorremoved_actors_t;
removed_actors_tm_removed_actors;
boolm_is_looping;
};
没有给add也加保护的原因是,不会在update函数内向ActorManager添加新对象。
当然,有可能在其他地方会有这样的需求,同样也做类似的保护即可。
问题虽然不大,但是几次碰到类似的错误了。记录之,并强制要求自己,
在遇到会对容器内的对象做for…处理时,一定要谨慎的检查一下remove接口。
而Actor类的实现是这样:
有一天,在给Actor添加逻辑的时候,update函数变成了这样
再往下
然后……
classActorManager
{
public:
voidupdate()
{
m_is_looping=true;
for(actors_t::const_iteratoritr=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_iteratoritr=m_removed_actors.begin();
itr!=m_removed_actors.end();++itr)
{
Actor*actor=*itr;
m_actors.erase(actor->get_id());
}
m_removed_actors.clear();
}
}
voidadd(Actor*actor)
{
m_actors[actor->get_id()]=actor;
}
voidremove(Actor*actor)
{
if(!m_is_looping)
m_actors.erase(actor->get_id());
else
m_removed_actors.push_back(actor);
}
private:
typedefstd::mapactors_t;
actors_tm_actors;
typedefstd::vectorremoved_actors_t;
removed_actors_tm_removed_actors;
boolm_is_looping;
};
没有给add也加保护的原因是,不会在update函数内向ActorManager添加新对象。
当然,有可能在其他地方会有这样的需求,同样也做类似的保护即可。
问题虽然不大,但是几次碰到类似的错误了。记录之,并强制要求自己,
在遇到会对容器内的对象做for…处理时,一定要谨慎的检查一下remove接口。
相关文章推荐
- C++中的静态对象需要注意的几个问题
- C++中用对象管理资源时需要注意的问题
- Android中继承Parcelable序列化对象需要注意的问题,记录!
- spring 容器后处理器 BeanFactoryPostProcessor 使用需要注意的一个问题
- Java遍历容器注意问题
- 学习C++需要注意的问题
- C++遍历container删除需要注意地方
- 在c#里调用C++的dll时,需要注意的一些问题
- 关于创建Immutable对象时需要注意的几个问题
- C++中派生类重写基类重载函数时需要注意的问题:派生类函数屏蔽基类中同名函数
- C++容器元素遍历的问题
- c# - 外部对象作为参数调用方法时需要注意的问题
- 32位C/C++程序移植到64位系统时需要注意的问题
- C&C++多系统集成需要注意的问题
- 命令行下的C++程序转换成VC的MFC程序需要注意的问题
- 使用 NetShareEnum 遍历本地共享目录需要注意的问题
- C++ 需要注意的一些问题
- C++需要注意的细节问题(无限期添加)
- c++两个类相互调用需要注意的问题
- 使用C/C++编译预处理时需要注意的问题(宏相关问题)