Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to modify mutable members of objects inside sets?

I was curious as to whether the following scenario is safe.

I have the following class definitions:

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

I then store a group of these inside an std::set as follows:

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;

I mark RemainingTurns as mutable because I want to be able to change it without haing to constantly erase/insert into the set. I.e.

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

I'm concerned because it seems possible for this to mess up the ordering within the set, meaning I can't guarantee the set will always be sorted by effect->GetPrority()

If that's true, is there a safe way (such as not have RemainingTurns form part of the key) to do this besides copying, modifying, erasing then inserting what I need to change?

EDIT:

@ildjarn - sorry, I didn't think that mattered. It just returns an int stored within StatusEffect. That int is guaranteed not to change over the runtime of the program.

int StatusEffect::GetPriority() const
{
    return StatusPriority;
}
like image 738
Megatron Avatar asked May 20 '11 06:05

Megatron


People also ask

Can we add mutable items in set?

A set is mutable, i.e., we can remove or add elements to it. Set in python is similar to mathematical sets, and operations like intersection, union, symmetric difference, and more can be applied.

Are sets immutable in C++?

Modifications that do not break the sorting order are changes in those parts of the contained elements that do not contribute to the sorting order. The C++ Standard does not specify whether the iterator of a set container (type set<T>:: iterator) is a mutable or immutable iterator.

Why might you declare member data mutable?

Adding mutable to a variable allows a const pointer to change members. mutable is particularly useful if most of the members should be constant but a few need to be updatable. Data members declared as mutable can be modified even though they are the part of object declared as const.

Are sets immutable?

Sets are unordered. Set elements are unique. Duplicate elements are not allowed. A set itself may be modified, but the elements contained in the set must be of an immutable type.


1 Answers

Changing data that affects the ordering of an object will indeed break the invariants of associative containers, but because ActiveStatusEffect::ReminaingTurns is not involved in the ordering of ActiveStatusEffect objects whatsoever, keeping it mutable and modifying its value is perfectly harmless.

I'm concerned because it seems possible for this to mess up the ordering within the set, meaning I can't guarantee the set will always be sorted by effect->GetPrority()

It's a std::set<StatusEffects::ActiveStatusEffect, ASECmp>; how could it sort by any criteria other than that defined by ASECmp?

like image 106
ildjarn Avatar answered Sep 22 '22 12:09

ildjarn