我很好奇以下情况是否安全。
我有以下类定义:
class ActiveStatusEffect
{
public:
StatusEffect* effect;
mutable int ReminaingTurns;
ActiveStatusEffect() : ReminaingTurns(0)
{
}
//Other unimportant stuff down here
}
然后我将一组这些存储在std :: set中,如下所示:
struct ASECmp
{
bool operator ()(const StatusEffects::ActiveStatusEffect &eff1, const StatusEffects::ActiveStatusEffect &eff2)
{
return eff1.effect->GetPriority() < eff2.effect->GetPriority();
}
};
std::set<StatusEffects::ActiveStatusEffect, ASECmp> ActiveStatusEffects;
我将RemainingTurns标记为可变,因为我希望能够更改它而不必不断地擦除/插入到集合中。即。
void BaseCharacter::Tick(Battles::BattleField &field, int ticks)
{
for (auto effect = ActiveStatusEffects.begin(); effect != ActiveStatusEffects.end();)// ++index)
{
auto next = effect;
++next;
if (effect->effect->HasFlag(StatusEffects::STATUS_FLAGS::TickEffect) && effect->ReminaingTurns > 0)
{
effect->effect->TickCharacter(*this, field, ticks);
--effect->ReminaingTurns;
}
if (effect->ReminaingTurns == 0)
{
ActiveStatusEffects.erase(effect);
}
effect = next;
}
}
我很担心,因为这似乎有可能弄乱集合中的排序,这意味着我不能保证集合总是按效果排序 - > GetPrority()
如果这是真的,除了复制,修改,删除然后插入我需要更改的内容之外,还有一种安全的方法(例如没有RemainingTurns构成密钥的一部分)吗?
编辑:
@ildjarn - 对不起,我觉得不重要。它只返回一个存储在StatusEffect中的int。保证int不会改变程序的运行时。
int StatusEffect::GetPriority() const
{
return StatusPriority;
}
答案 0 :(得分:7)
更改影响对象排序的数据确实会破坏关联容器的不变量,但因为ActiveStatusEffect::ReminaingTurns
不参与ActiveStatusEffect
个对象的排序,所以保持它mutable
并且修改它的价值是完全无害的。
我很担心,因为这似乎有可能弄乱集合中的排序,这意味着我不能保证集合总是按效果排序 - > GetPrority()
这是std::set<StatusEffects::ActiveStatusEffect, ASECmp>
;如何按照ASECmp
定义的标准排序?
答案 1 :(得分:2)
如果你改变std :: set中某些东西的键,你就会在未定义的行为中离开 - 就像那样简单。它不仅会“搞砸订单”,而且可能会完全无法正常工作。
答案 2 :(得分:0)
如果密钥与实际对象无关,或仅与其中的一部分无关,那么您应该考虑使用地图而不是集合:
std::map< int, ActiveStatusEffect > m;
ActiveStatusEffect x = create();
m[ x.effect->GetPriority ] = x; // !!!
您的代码的其他问题是您应该使用一些封装(用户代码不应该访问类的内部(即成员不应该是公共的)。