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

Update element in a set of pointer of elements before deletion

本文关键字:元素 一组 指针 删除 更新      更新时间:2023-10-16

我有一些在unordered_map中分配的类实例。我也有不同的容器,用于存储指向这些元素的指针,这些元素具有不同的顺序。这意味着,例如,我有一个 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(元素(。

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

用作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

科里鲁的现场演示

那么,我可以修改关键field_2然后立即调用删除和插入吗?

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

或者删除会失败,因为field_2的值可能不一致?

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

(我认为这将取决于实现,但我想确保(

未定义的行为部分不依赖于实现。