Безопасно ли изменять изменяемые члены объектов внутри наборов? - PullRequest
6 голосов
/ 20 мая 2011

Мне было любопытно, безопасен ли следующий сценарий.

У меня есть следующие определения классов:

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 как изменяемые, потому что я хочу иметь возможность изменить его, не имея необходимости постоянно стирать / вставлять в набор. * 1009 Т.е. *

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, являющийся частью ключа), кроме копирования, изменения, удаления и вставки того, что мне нужно изменить?

EDIT:

@ ildjarn - прости, я не думал, что это имело значение. Он просто возвращает int, сохраненный в StatusEffect. Это int гарантированно не изменится во время выполнения программы.

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

Ответы [ 3 ]

7 голосов
/ 20 мая 2011

Изменение данных, влияющих на упорядочение объекта, действительно нарушит инварианты ассоциативных контейнеров, но поскольку ActiveStatusEffect::ReminaingTurns не участвует в упорядочении ActiveStatusEffect объектов вообще, его сохранение mutable и изменение его значения совершеннобезвредный.

Я обеспокоен тем, что для этого представляется возможным испортить порядок в наборе, то есть я не могу гарантировать, что набор всегда будет отсортирован по эффекту-> GetPrority ()

Это std::set<StatusEffects::ActiveStatusEffect, ASECmp>;как это можно отсортировать по любым критериям, отличным от ASECmp?

2 голосов
/ 20 мая 2011

Если вы измените ключ чего-либо в std :: set, вы окажетесь в стране неопределенного поведения - все просто.Мало того, что это "испортит порядок", но и набор, вероятно, перестанет работать правильно.

0 голосов
/ 20 мая 2011

Если ключ не связан с реальным объектом или только его частью, то вам следует рассмотреть возможность использования карты, а не набора:

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

Другие проблемы с вашим кодом заключаются в том, чтоиспользовать некоторую инкапсуляцию (пользовательский код не должен получать доступ к внутренним объектам класса (т.е. члены не должны быть открытыми).

...