正如所有标准关联容器,set 和 multiset 保持它们的元素有序,容器的正确行为依赖于它们保持有序,如果改变一个元素的值,新值不在正确的位置,将破坏容器的有序性。
对于 map 和 multimap 容器,改变容器里一个键值的程序不能编译,
map<K, V> 或 multimap<K, V> 类型的对象中的元素类型是 pair<const K, V>,
键的类型是 const K 不能改变。
而对于 set 和 multiset 为 set<T> 和 multiset<T>,非 const 的原因:
想要元素 T 中,非元素的键的部分可以被修改
1. 如果不关心移植性,想要改变 set 或 multiset 中元素的值,只要确定不要改变元素的键的部分
2. 如果在乎移植性,就认为 set 和 mutiset 中的元素不能被修改,至少不能在没有映射的情况下。
映射掉引用:
1 if( i != se.end() ) 2 { 3 const_cast<Employee &> (*i).setTitle("Corporate Deity"); //映射掉 *i 的常量性 4 }
告诉编译器把映射的结果当作一个(非常数)Employee 的引用,然后在引用上调用setTitle
如果总可以工作而且总是安全的改变 set、multiset、map 或 multimap 里的元素,通常按五个步骤去做:
1. 定位你想要改变的容器元素
2. 拷贝一份要修改的元素
3. 修改副本
4. 从容器里删除元素,通常通过调用 erase
5. 把新值插入容器
以安全可移植的方式写:
1 EmpIDSet se; 2 Employee selectedID; 3 . . . 4 EmpIDSet::iterator i = se.find( selectedID ); // 第一步:找到要改变的元素 5 if( *i != se.end() ) 6 { 7 Employee e(*i); // 第二步:拷贝这个元素 8 se.erase( i++ ); // 第三步:删除这个元素,自增这个迭代器以保持它有效 9 e.setTitle( "Corporate Deity" ); // 第四步:修改这个副本 10 se.insert(i, e); // 第五步:插入新值,位置和原来位置一样 11 }
总的来说,避免原地修改 set 和 multiset 的键