2011-05-20 68 views
5

我很好奇以下情况是否安全。修改组内对象的可变成员是否安全?

我有下面的类定义:

class ActiveStatusEffect 
{ 
public: 
    StatusEffect* effect; 
    mutable int ReminaingTurns; 
    ActiveStatusEffect() : ReminaingTurns(0) 
    { 
    } 
    //Other unimportant stuff down here 
} 

我然后存储一组这些一个std ::里面设置如下:

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

听起来像是['的std :: priority_queue <>'](HTTP的情况下://www.sgi的.com /技术/ STL/priority_queue.html)容器代替;对于更复杂的情况,请参见[升压多指标(http://www.boost.org/doc/libs/1_37_0/libs/multi_index/doc/index.html ) – sehe 2011-05-20 06:28:27

+0

@sehe:可以事先ity处理更改密钥而不重新插入? – 2011-05-20 06:30:40

+2

当我们看不到'StatusEffect :: GetPriority()'的实现时,我们怎么可能知道'RemainingTurns''可变性是否很重要? – ildjarn 2011-05-20 06:30:47

回答

6

影响的对象将打破的确关联容器的不变量的排序,但由于ActiveStatusEffect::ReminaingTurns不参与ActiveStatusEffect对象的任何排序,保持mutable并修改它的值更改数据是完全无害的。

我很担心,因为它这似乎可能搞乱集内的排序,这意味着我不能保证集将始终效应 - 排序> GetPrority()

这是一个std::set<StatusEffects::ActiveStatusEffect, ASECmp>;除了ASECmp定义的标准之外,它如何排序呢?

+0

我担心它打破了关键,未来的插入没有被插入正确地发生一次 – Megatron 2011-05-20 07:04:55

+0

@ user127817:但是,对于标准的有序关联容器而言,“ActiveStatusEffect :: ReminaingTurns”并不是密钥身份的一部分,因为它在“ActiveStatusEffect”排序中没有考虑到。也就是说,你在将来打破某些事情的唯一风险是通过改变'ActiveStatusEffect'的排序逻辑来以某种方式使用'ReminaingTurns'。 – ildjarn 2011-05-20 17:23:22

2

如果您更改std :: set中的某个键的关键字,那么您将在Undefined Behavior land中关闭 - 就像那样简单。它不仅会“搞乱顺序”,而且该设置可能会停止正常工作。

0

如果关键是无关的实际对象,或者只是它的一部分,那么你应该考虑使用地图,而不是一组:

std::map< int, ActiveStatusEffect > m; 
ActiveStatusEffect x = create(); 
m[ x.effect->GetPriority ] = x;  // !!! 

与您的代码的其他问题是,你应该使用一些封装(用户代码不应该访问类的内部(即,成员不应公开)

相关问题