删除前更新一组元素指针中的元素

Update element in a set of pointer of elements before deletion

我在 unordered_map 中分配了一些 class 实例。我还有不同的容器,它们以不同的顺序存储指向这些元素的指针。这意味着,例如,我有一个 std::set 指向映射中分配的元素的指针,按实例字段的子集排序。

因为我可以访问真实元素,所以我可以更改它们的字段,但我知道我不应该在用于集合排序的字段上这样做。事实上,在更改那些字段之前我需要做的是从集合中删除对象的指针,更改那些字段并再次将其插入回去,就像这样:

set<Element*, Comparator> s; // Elements ordered by field_2

s.erase(element);
element->field_2 = 4;
s.insert(element);

但是,其他维护不同顺序的容器是我自己实现的,我知道我可以更改那些值,然后通知容器字段已更新。所以我想知道我是否可以将这些说明的顺序更改为这个:

element->field_2 = 4;
s.erase(element);
s.insert(element);

我想这样做的原因是我希望所有这些容器共享同一个接口。所以理想情况下我想更改字段然后调用容器的方法 container.value_updated(element).

那么,我可以修改关键的field_2,然后立即调用删除和插入吗?或者删除会失败,因为 field_2 的值可能不一致? (我认为这将取决于实现,但我想确定)

So, can I modify the critical field_2 and then immediately call delete & insert?

没有。这有可能破坏集合中指针的顺序。

Or the deletion will fail since the value of field_2 can be inconsistent?

这是一个明显的可能性。但是,此时您正在查看未定义的行为。无法预测会发生什么。

(I think this will be implementation dependent but I want to make sure)

未定义的行为部分与实现无关。

std::set 中用作键的数据可能不会更改。否则,std::set 的顺序将被破坏,std::set 中的寻址元素将无法再工作。

出于好奇,我试着用错误的方式去做。

虽然我知道这是未定义的行为,但我得到了这个 运行 – 一个很好的证明坏事发生了:

#include <iostream>
#include <set>
#include <vector>

typedef int Entry;

struct Less {
  bool operator()(const Entry *p1, const Entry *p2) const
  {
    return *p1 < *p2;
  }
};

int main()
{
  const int N = 10;
  std::vector<int> data;
  for (int i = 0; i < N; ++i) data.push_back(i);
  std::set<Entry*, Less> set;
  for (int &value : data) set.insert(&value);
  // do it wrong
  data[2] = 12;
  set.erase(&data[2]);
  set.insert(&data[2]);
  // check result
  for (const Entry *pValue : set) std::cout << ' ' << *pValue;
  std::cout << '\n';
  // done
  return 0;
}

输出:

 0 1 12 3 4 5 6 7 8 9 12

Live Demo on coliru