STL set 容易引起误解的一个地方
#include <set>
#include <string>
#include <iostream>
using namespace std;
using std::set;
using std::string;
struct student {
string name;
int grade;
student(string const& name_, int grade_)
: name(name_)
, grade(grade_)
{}
bool operator<(student const& rhs) const
{
return name < rhs.name;
}
bool operator==(student const& rhs) const
{
return name == rhs.name;
}
};
int main(void)
{
set<student> students;
students.insert(student("Li Lei", 5));
students.insert(student("Han Meimei", 5));
students.insert(student("Jim Green", 5));
for (set<student>::iterator i = students.begin();
students.end() != i;
++i)
{
(i->grade)+=1;
}
return 0;
}
STL set是只读机制,set 的只读制度是非常龌龊的, 简而言之, 只要你敢往这个坑里面放, 你就得接受它们以后再也无法修改的命运
student 类的 key 是 name, 跟 grade 没有关系, 原则上来说, 修改后者并不会破坏 set 的存储结构. 然而, 编译器一棒子打死, 不许改, 除非剩下的成员全部 mutable 修饰.
只读制度悲剧的根源在于, set 所谓的 key 撑死只是个假象, value_type 这玩意儿就是 key_type 本身, 既然名份这个大框框定了, 那再怎么折腾也只是折腾, 二奶再怎么被临幸也是二奶, 总也到不了拿证那一步.
伪 key 导致的不仅仅是不能改, 重要的是还不能查! 看看 set::find 函数的参数, 要的又是阴魂不散的 key_type. 这意味着什么? 意味着 Han MM 同学报出她名字的时候, 还查不出她几年级, 而必须要利用她的名字, 伪造一个充气娃娃放进去才能找到! 看到这里我就败了, 这明摆着就是不让我用 set, 让我转投 map 么? 一个也许可行的方案是
#include <map>
#include <string>
using std::map;
using std::string;
struct student_periphery {
int grade;
};
map<string, student_periphery> students;
Dev-Cpp g++下编译不通过, 但是在aix xlC下通过的代码
可能原因:
set returns const iterators (the standard says set::iterator is const, and that set::const_iterator and set::iterator may in fact be the same type - see 23.2.4/6 in n3000.pdf) because it is an ordered container. If it returned a regular iterator, you'd be allowed to change the items value out from under the container, potentially altering the ordering.没办法,如果想修改的话只能先删除再添加咯。这点stl做的有点傻阿。我改后面那个值与你索引的那个有嘛关系,为啥不可以修改捏?
只应该对索引的那个键进行const保护塞。。。
set一般是用红黑树来实现的,所以结点的值不能修改,因为改了之后会对树造成破坏(不再是排序二叉树),之后对set的任何操作 都可能得到不确定的结果。
如果要修改,你可以erase掉某个结点修改后再重新insert
标准的STL这里肯定是不能改的,所以你的程序会有严重的移植问题
由于set不是一个简单的线性结构,如果能够修改,就不能防止人为地修改键值,而这会造成set的崩溃。
在我的VS2008中这段代码也可以很好的运行,可能在VS2008中有这样的机制吧
Reference:
http://www.taoyard.net.cn/?p=79
http://super-jiju.spaces.live.com/blog/cns!806C498DDEE76B61!787.entry
http://www.lslnet.com/linux/dosc1/26/linux-219500.htm