C++中遍历容器对象时需要注意的问题

假设有这样一个管理对象的容器 ActorManager,其实现大概为

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 actors_t;
actors_t m_actors;
};

 

而Actor类的实现是这样:

class Actor
{
public:
void update()
{
// ...

}

有一天,在给Actor添加逻辑的时候,update函数变成了这样

void update()
{
// ...

update_buff_effect();

// ...
}

 

再往下

 

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循环里删除对象,而实际上却有几次遇到类似的问题。
有些问题没有这么明显,但也都是出在遍历容器对象的过程中,某个执行函数删除了窗口里的对象,从而导致迭代器失效。
 
修改的方法很简单,给ActorManager添加一个待删除对象列表
在remove方法中并不真正删除对象,而是等到update中循环结束后再删除对象。
代码看起来会是这样:
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 actors_t;
actors_t m_actors;

typedef std::vector removed_actors_t;
removed_actors_t m_removed_actors;
bool m_is_looping;
};

 

没有给add也加保护的原因是,不会在update函数内向ActorManager添加新对象。

当然,有可能在其他地方会有这样的需求,同样也做类似的保护即可。

 

 

问题虽然不大,但是几次碰到类似的错误了。记录之,并强制要求自己,

在遇到会对容器内的对象做for…处理时,一定要谨慎的检查一下remove接口。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值