考虑以下计划。它创建了一组指向内部的指针,并使用一个自定义的indrect_less比较器,它通过指向整数的值对集合进行排序。完成后,我然后更改其中一个指向整数的值。然后,可以看出集合的顺序不再排序(我想因为集合不知道某些事情发生了变化)。
(不介意C ++ 0x循环,我在VS2010上运行)
#include <iostream>
#include <set>
using namespace std;
struct indirect_less {
bool operator()(int* l, int* r) const
{
return *l < *r;
}
};
int main()
{
set<int*, indirect_less> myset;
int* a = new int(5);
int* b = new int(6);
int* c = new int(7);
myset.insert(a);
myset.insert(b);
myset.insert(c);
cout << "Set contains: ";
// (outputs: 5 6 7)
for (auto i = myset.begin(), end = myset.end(); i != end; ++i)
{
cout << **i << " ";
}
cout << endl << "Modifying *a" << endl;
*a = 9; // point of interest
cout << "Set contains: ";
// (outputs: 9 6 7 - unsorted order)
for (auto i = myset.begin(), end = myset.end(); i != end; ++i)
{
cout << **i << " ";
}
cout << endl;
cin.get();
return 0;
}
1)我正在调用未定义的行为吗?行myset
后的整个*a = 9;
状态是否无效?
2)唯一正确的方法是擦除然后重新插入a
?
3)运行*a = 9;
后,有没有办法重新平衡有关排序顺序的集合,具有明确定义的行为?
答案 0 :(得分:2)
是的,std::set
假定元素是不可变的。 possible,如果有危险,可在每次更改后自行重新排序。但我不推荐它:使用另一种集合类型。
答案 1 :(得分:1)
1)是的,set不允许修改它的元素。
2)除了删除旧值并插入新值外,您还可以用新构造的值替换旧值。
3)否
答案 2 :(得分:1)
1)我不知道行为是未定义的。此示例中的附加扭曲是集合的元素不会更改 - 集合中的每个元素都是指针。如果你在执行'* a = 9'之前和之后打印出集合的(指针)元素,我相信你会发现在赋值之前和之后指针值的顺序相同。改变的是一个集合元素指向的值。这是在集合的主持之外发生的,因此集合无法维持你想要的顺序。
2)合格的“是”。这将强制使用indirect_less()来对集合的元素进行排序。再次,请注意您通过每个解除引用的指针的值来排序集合的元素,指针。然而,正如你所描述的那样,这对我来说有些冒险。
从打印输出中的图例“Set contains:”,我假设这个例子努力形成一组整数。但是,定义的集合,即“set”实际上由指向整数的指针组成,而不是整数本身。我认为,期望和实际集合之间的这种不对齐是问题的根本原因。
3)见2)。