C++ STL
有关C++ STL的使用的一些注意点。
一、map
map在STL中定义为:
template < class Key, // map::key_type class T, // map::mapped_type class Compare = less<Key>, // map::key_compare class Alloc = allocator<pair<const Key,T> > // map::allocator_type > class map;
对于一般的使用来说,map<class key, class T>即可。但是对于key无法直接比较大小时,则需要对key类型重载<等操作符。详细代码如下:
#include<map> #include<string> #include<iostream> using namespace std; typedef struct tagStudentInfo { int nID; string strName; bool operator < (tagStudentInfo const& _A) const { //这个函数指定排序策略,按nID排序,如果nID相等的话,按strName排序 if(nID < _A.nID) return true; if(nID == _A.nID) return strName.compare(_A.strName) < 0; return false; } }StudentInfo, *PStudentInfo; //学生信息 int main() { //用学生信息映射分数 map<StudentInfo, int> mapStudent; map<StudentInfo, int>::iterator iter; StudentInfo studentInfo; studentInfo.nID = 1; studentInfo.strName = "student_one"; mapStudent.insert(pair<StudentInfo, int>(studentInfo, 90)); studentInfo.nID = 2; studentInfo.strName = "student_two"; mapStudent.insert(pair<StudentInfo, int>(studentInfo, 80)); for (iter=mapStudent.begin(); iter!=mapStudent.end(); iter++) cout<<iter->first.nID<<endl<<iter->first.strName<<endl<<iter->second<<endl; }
重载操作符时,注意一般应用const修饰,一个比较浅显的原因是,const对象只能调用const成员函数,对于可以比较的类来说,const对象当然也能够比较大小,因此某种程度上,不修改对象的函数都可以加上const。
上述代码中,tagStudentInfo类型的结构体无法直接比较大小,因此如果不重载小于<操作符,那么插入map的时候无法根据tagStudentInfo来判断是否相等或比较大小(C++中使用严格弱排序,即不允许a<b和b<a同时成立,而且等于是通过!(a<b)&&!(b<a) 来进行),编译器会对这种行对报错。
另一种解决办法,则是在map声明中加入第三个参数class Compare: map<class Key, class T, class compare>,使用class compare的函数对象来比较大小,即重载类operator()来实现,代码如下:
#include<map> #include<string> using namespace std; typedef struct tagStudentInfo { int nID; string strName; }StudentInfo, *PStudentInfo; //学生信息 class compare { public: bool operator() (StudentInfo const & _A, StudentInfo const & _B) const { if(_A.nID < _B.nID) return true; if(_A.nID == _B.nID) return _A.strName.compare(_B.strName) < 0; return false; } }; int main() { //用学生信息映射分数 map<StudentInfo, int, compare> mapStudent; StudentInfo studentInfo; studentInfo.nID = 1; studentInfo.strName = "student_one"; mapStudent.insert(pair<StudentInfo, int>(studentInfo, 90)); studentInfo.nID = 2; studentInfo.strName = "student_two"; mapStudent.insert(pair<StudentInfo, int>(studentInfo, 80)); }
map成员函数的返回值也需要注意。
1. insert()函数:返回由map<class key, class T>::iterator和bool类型组成的pair,即:
map<class key, class T> mp; pair<map<class key, class T>, bool> insert_itor = mp.insert(value_type(class key, class T)(key, T))
如插入成功,则返回插入的位置和true;若插入失败,则返回冲突的位置和false。
2. upper_bound(n)和lower_bound(n)函数:返回map<class key, class T>::iterator类型的迭代器,lower_bound(n)返回大于等于n的key位置的迭代器,upper_bound(n)返回大于n的key的位置的迭代器。equal_range()则返回一个由两个map<class key, class T>::iterator类型组成的pair,前者为lower_bound(n)的返回值,后者为upper_bound(n)的返回值。如果n不存在于map中,则equal_range()返回值的first和second()相等,这也可以用来判断元素是否存在于map中。
(上述代码来源于sunshinewave)
二、unordered_set/unordered_map
两者在STL中的定义为:
template < class Key, // unordered_set::key_type/value_type class Hash = hash<Key>, // unordered_set::hasher class Pred = equal_to<Key>, // unordered_set::key_equal class Alloc = allocator<Key> // unordered_set::allocator_type > class unordered_set; template < class Key, // unordered_map::key_type class T, // unordered_map::mapped_type class Hash = hash<Key>, // unordered_map::hasher class Pred = equal_to<Key>, // unordered_map::key_equal class Alloc = allocator< pair<const Key,T> > // unordered_map::allocator_type > class unordered_map;
unordered_set和unordered_map在STL中有着类似的构造:都是通过hash函数将key值转化为相应的hash值来进行储存,检索时间复杂度皆为O(1)。对于基本数据类型,如int、char等整形值,STL中定义的hash函数只是单纯地将整形转换为size_t型值,然后对当前hashtable的bucket数量取模即可;同时STL也对string型对象提供了一个hash函数。但是对于自定义类型的key值,unordered_set和unordered_map需要自定义hash函数和以及equal_to函数。
对于hash函数,可以使用函数对象。例如,对于x、y坐标值在0~99的点序列,可以将100*x+y作为其hash值(相当于100进制的整数),于是可以以下面的形式定义hash函数:
#include<bits\stdc++.h> //bits\stdc++.h包含所有头文件 不过编译时间较慢 using namespace std; struct myHash { size_t operator()(pair<int, int> __val) const { return static_cast<size_t>(__val.first * 100 + __val.second); } }; int main() { unordered_set<pair<int, int>, myHash> S; int x, y; while (cin >> x >> y) S.insert(make_pair(x, y)); for (auto it = S.begin(); it != S.end(); ++it) cout << it->first << " " << it->second << endl; return 0; }
对于equal_to函数,则可以重载==操作符或者使用函数对象来实现。类似于map中操作符<的重载和class compare的函数对象来实现。
三、string和wstring
wstring实现对wchar_t类型字符的操作,用于满足非ASCII字符的需求。对于wchar_t类型,STL中都有与string相应的操作,如wcout、wcin等。对于汉字来说,string也可以进行储存,但是是通过两个char储存一个汉字的方式实现的,因此对于汉字字符串的操作需要通过特殊方式实现。而一个wchar_t能储存一个汉字,因此能完全满足汉字字符串的需求。但是在使用wchar_t时,需要通过imbue()函数指定输出时的区域语言对象,如:cout.imbue(locale("chs"))。详细代码如下:
#include<iostream> #include<string> #include<locale.h> using namespace std; #define tab "\t" int main() { locale def; cout<<def.name()<<endl; locale current = cout.getloc(); cout<<current.name()<<endl; //chage to chinese cout.imbue(locale("chs")); current=cout.getloc(); cout<<current.name()<<endl; //上面是说明locale的用法,下面才是本例的内容,因为其中用到了imbue函数 cout<<"*********************************"<<endl; //为了保证本地化输出(文字/时间/货币等),chs表示中国,wcout必须使用本地化解析编码 wcout.imbue(std::locale("chs")); //string 英文,正确颠倒位置,显示第二个字符正确 string str1("ABCabc"); string str11(str1.rbegin(),str1.rend()); cout<<"UK\ts1\t:"<<str1<<tab<<str1[1]<<tab<<str11<<endl; //wstring 英文,正确颠倒位置,显示第二个字符正确 wstring str2=L"ABCabc"; wstring str22(str2.rbegin(),str2.rend()); wcout<<"UK\tws4\t:"<<str2<<tab<<str2[1]<<tab<<str22<<endl; //string 中文,颠倒后,变成乱码,第二个字符读取也错误 string str3("你好么?"); string str33(str3.rbegin(),str3.rend()); cout<<"CHN\ts3\t:"<<str3<<tab<<str3[1]<<tab<<str33<<endl; //正确的打印第二个字符的方法 cout<<"CHN\ts3\t:RIGHT\t"<<str3[2]<<str3[3]<<endl; //中文,正确颠倒位置,显示第二个字符正确 wstring str4=L"你好么?"; wstring str44(str4.rbegin(),str4.rend()); wcout<<"CHN\tws4\t:"<<str4<<tab<<str4[1]<<tab<<str44<<endl; //只有char类型的string时才可以如此构造 wstring str5(str1.begin(),str1.end()); wstring str55(str5.rbegin(),str5.rend()); wcout<<"CHN\tws5\t:"<<str5<<tab<<str5[1]<<tab<<str55<<endl; //如此构造将失败!!!! wstring str6(str3.begin(),str3.end()); wstring str66(str6.rbegin(),str6.rend()); wcout<<"CHN\tws6\t:"<<str6<<tab<<str6[1]<<tab<<str66<<endl; return 0; }
code::blocks下代码编码出错(error: converting to execution character set: Illegal byte sequence),加上-finput-charset=GB2312等之后仍然有错。待进一步验证问题。。。
(持续更新)

浙公网安备 33010602011771号