修改集合内对象的可变成员是否安全?

发布于 2024-11-08 03:33:57 字数 1719 浏览 0 评论 0原文

我很好奇以下场景是否安全。

我有以下类定义:

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

树深时见影 2024-11-15 03:33:57

更改影响对象排序的数据确实会破坏关联容器的不变量,但由于 ActiveStatusEffect::ReminaingTurns 不涉及 ActiveStatusEffect 对象的排序,因此它是可变的,修改它的值是完全无害的。

我很担心,因为这似乎可能会扰乱集合内的顺序,这意味着我无法保证集合将始终按效果排序->GetPrority()

这是一个 std::set;它怎么能按照 ASECmp 定义的标准以外的任何标准进行排序?

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?

○愚か者の日 2024-11-15 03:33:57

如果你改变了 std::set 中某些东西的键,你就会进入未定义行为的境地 - 就这么简单。它不仅会“打乱顺序”,而且该装置可能会完全停止正常工作。

If you change the key of something in a std::set you are off in Undefined Behaviour land - simple as that. Not only will it "mess up the ordering", but the set will probably stop working correctly altogether.

就此别过 2024-11-15 03:33:57

如果键与实际对象无关,或者只是其中的一部分,那么您应该考虑使用映射而不是集合:

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

代码的其他问题是您应该使用某种封装(用户代码不应该访问类的内部结构(即成员不应该是公共的)。

If the key is unrelated to the actual object, or only a part of it, then you should consider using a map rather than a set:

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

Other issues with your code is that you should use some encapsulation (user code should not get access to the internals of the class (i.e. members should not be public).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文