我认为STL容器集和map以严格的弱顺序提供元素。但是,我发现如果通过解除引用获取迭代器并通过解除引用更改元素的值,则它不会恢复顺序,这违反了23.1.2.2和23.3.3.2。这是代码
int nv = 3;
set<int> s = set<int>();
s.insert(5);
s.insert(10);
s.insert(20);
s.insert(30);
for(set<int>::const_iterator cit = s.begin(); cit != s.end(); ++cit)
cout<<*cit<<" ";
cout <<endl;
set<int>::iterator it = s.find(10);
*it = nv;
for(set<int>::const_iterator cit = s.begin(); cit != s.end(); ++cit)
cout<<*cit<<" ";
cout <<endl;
s.insert(40);
for(set<int>::const_iterator cit = s.begin(); cit != s.end(); ++cit)
cout<<*cit<<" ";
cout <<endl;
产生
5 10 20 30
5 3 20 30
5 3 20 30 40
这是我的STL版本(MS VS 2008)中的错误吗?或者我错了吗?
答案 0 :(得分:4)
std::map
和std::set
仅对插入执行排序。如果您更改现有项目的键/值,则不会发生任何魔法,结果可能未定义。
要获得所需效果,您必须删除原始元素,然后插入一个新元素。
答案 1 :(得分:4)
set的iterator和const_iterator都是常量迭代器。您不能修改set的值,只能删除和插入。
答案 2 :(得分:2)
看起来像那个版本的STL中的错误。
在我的g ++上,我收到以下错误:
t2.cpp:18:8: error: assignment of read-only location ‘it.std::_Rb_tree_const_iterator<_Tp>::operator* [with _Tp = int, const _Tp& = const int&]()’
答案 3 :(得分:1)
通常情况下,您无法通过迭代器修改关联容器元素的键部分。代码根本不会编译。
如果您的标准库实现允许*it = nv
赋值,那么它必须是该实现的一个怪癖。 AFAIK,允许编译此作业并非严格违法。这更像是一个实施质量问题。
分配不会使用Comeau实现进行编译。 MS的实施明显不那么严格。
答案 4 :(得分:1)
更改std::set
中的元素可能违反内部排序并破坏您的数据结构。只有一些STL实现通过禁止修改iterator
指向的内容来防止这种情况,因此您必须自己强制执行该约束。
这就像通过调用std::vector
(以腾出空间)并使用指针算法来编写reserve
的逻辑结尾 - 你可以这样做,但它会破坏你的std::vector
如果要更改集合中的元素,这应该有效:
std::set<int> my_set;
// initialize my_set ...
std::set<int>::iterator itr = my_set.find(10);
if (itr != my_set.end()) {
my_set.erase(itr++); // ++ avoids invalidating iterator
my_set.insert(3);
}
如果您想继续使用它,您只需要增加itr
。
(来源:有效STL ,“第22项,”Scott Meyers)
答案 5 :(得分:0)
std::map
和std::set
不提供 严格的弱订购,他们需要一个。您必须提供排序(默认值为std::less
,适用于int
)。
如果您更改了set
或map
元素的排序方式,那么由于排序不稳定,您违反了要求。