我在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(element)。
那么,我可以修改关键字段_2,然后立即调用delete&insert吗?否则删除会失败,因为field_2的值可能不一致? (我认为这将取决于实现,但我想确保)
答案 0 :(得分:1)
因此,我可以修改关键的
field_2
,然后立即调用delete&insert吗?
不。这有可能破坏集合中指针的顺序。
还是因为
field_2
的值可能不一致而导致删除失败?
这是一种明显的可能性。但是,此时,您正在查看未定义的行为。无法预测会发生什么。
(我认为这将取决于实现,但我想确定)
未定义行为部分与实现无关。
答案 1 :(得分:1)
在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