2011-05-20 15 views
5

Tenía curiosidad sobre si el siguiente escenario es seguro.¿Es seguro modificar miembros mutables de objetos dentro de conjuntos?

que tienen las siguientes definiciones de clases:

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

entonces almacenar un grupo de éstos dentro de un std :: set de la siguiente manera:

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; 

taco RemainingTurns como mutable porque quiero ser capaz de cambiarlo sin tener que borrar/insertar constantemente en el conjunto. Es decir.

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

que a mí respecta, ya que parece posible que esto desordenar el orden dentro del conjunto, lo que significa que no puedo garantizar el conjunto será siempre ordenadas según la efecto-> GetPrority()

Si eso es cierto, ¿hay una manera segura (como no tener Remanente de Formas formando parte de la clave) para hacer esto además de copiar, modificar, borrar y luego insertar lo que necesito cambiar?

EDIT:

@ildjarn - lo siento, no pensé que importaba. Simplemente devuelve un int almacenado dentro de StatusEffect. Que int se garantiza que no cambiará durante el tiempo de ejecución del programa.

int StatusEffect::GetPriority() const 
{ 
    return StatusPriority; 
} 
+0

Suena como un caso para ['std :: priority_queue <>'] (http: //www.sgi .com/tech/stl/priority_queue.html) contenedor en su lugar; para escenarios más complejos, vea [Boost MultiIndex] (http://www.boost.org/doc/libs/1_37_0/libs/multi_index/doc/index.html) – sehe

+0

@sehe: ¿Puede un previo ¿Manejan las llaves cambiantes sin reinserción? –

+2

¿Cómo podemos saber si la mutabilidad de 'Remaneciendo'' importa cuando no podemos ver la implementación de' StatusEffect :: GetPriority() '? – ildjarn

Respuesta

6

datos Cambio que afecta a la ordenación de un objeto hecho va a romper los invariantes de contenedores asociativos, sino porque ActiveStatusEffect::ReminaingTurns no está involucrado en el orden de los objetos en absoluto ActiveStatusEffect, manteniéndolo mutable y modificar su valor es totalmente inofensiva.

que a mí respecta, ya que parece posible que esto desordenar el orden dentro del conjunto, lo que significa que no puedo garantizar el conjunto será siempre ordenadas según la efecto-> GetPrority()

Es un std::set<StatusEffects::ActiveStatusEffect, ASECmp>; ¿Cómo podría clasificarse por cualquier criterio que no sea el definido por ASECmp?

+0

Me preocupaba que se rompieran las claves, y las futuras inserciones no se insertaran correctamente una vez que ocurre – Megatron

+0

@ user127817: Pero 'ActiveStatusEffect :: ReminaingTurns' no es parte de la identidad de la clave en lo que respecta a los contenedores asociativos ordenados estándar, porque no se tiene en cuenta dentro del orden' ActiveStatusEffect'. Es decir, el único riesgo que corres de romper algo en el futuro es cambiando la lógica de ordenamiento de 'ActiveStatusEffect' para usar' ReminaingTurns' de alguna manera. – ildjarn

2

Si cambia la clave de algo en un std :: set usted está fuera de la tierra en un comportamiento indefinido - simple como eso. No solo "estropeará el orden", sino que probablemente el conjunto deje de funcionar correctamente.

0

Si la clave no está relacionada con el objeto real, o sólo una parte de ella, entonces usted debería considerar el uso de un mapa en lugar de un conjunto:

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

Otros problemas con su código es que se debe utilizar alguna encapsulación (el código de usuario no debería tener acceso a las partes internas de la clase (es decir, los miembros no deberían ser públicos).

Cuestiones relacionadas