[STL] __gnu_cxx::hash_map使用中的一些問題,
今天看《libstdc++ manual 20110201》中提到這個hash_map是為了向後相容SGI/HP的代碼,但是已經被廢棄了,取而代之的是C++0x中的unordered_map/unordered_multimap,在tr1檔案夾中(老版本的編譯器一般不帶這個檔案夾)。
==============================================================================
這個不是gcc標準庫的一部分,而是擴充ext中的一個功能,他提供了一個雜湊表的實現。定義如下:
template<class _Key, class _Tp, class _HashFcn = hash<_Key>,<br /> class _EqualKey = equal_to<_Key>, class _Alloc = allocator<_Tp> ><br /> class hash_map;<br />
可見,如果定義完整的hash_map,需要提供<key類型,value類型,雜湊函數,key相等判斷函數,value類型記憶體 Clerk>等5個模板參數,由於後三個都有預設值,所以一般我們只需要提供前兩個。
1>
定義__gnu_cxx::hash_map<string, int> myHash;不會出錯,然而一旦對myHash進行操作,就會出現編譯錯誤,“instantiated
from here”,這是因為gnu版本的hash_map只實現了有限的幾個hash模板函數(見第三個模板參數,這些函數在hash_fun.h中),而這些函數裡包括hash<const
char*>,但是不包括hash<std::string>的執行個體化。解決辦法是定義雜湊表前自己定義一個執行個體,這樣編譯器就知道調用這個函數了。
namespace __gnu_cxx<br />{<br />template<> struct hash<std::string><br />{<br />size_t operator()(const std::string &s) const{ return hash(s.c_str()); }<br />}<br />}<br />
2>
發現了gnu幫我們實現了hash<const char*>/hash<char*>的版本,那麼實際上,有時候就可以直接利用這個版本了。然而還是會出現新的問題:
__gnu_cxx::hash_map<char*, int> myHash;<br />char name1[10] = "panda";<br />char name2[10] = "panda";<br />myHash[name1] = 1;<br />__gnu_cxx::hash_map<char*, int>::iterator hit = myHash.find( name2 );<br />if( myHash.end() == hit ) printf( "Not Find\n" );<br />
你會發現,雖然name1和name2都是panda,但是插入了name1,用name2去尋找時,還是查無結果。這是涉及到第四個模板參數,判斷key相等,預設的是std::equal_to,而這個函數的定義是用operator==來進行判斷的,指標的相等當然就是地址一樣了,而name1和name2的地址顯然不同。解決辦法是用自己指定的函數模板替代預設的。
template <class _Tp><br />struct my_equal_to : public binary_function<_Tp, _Tp, bool><br />{<br /> bool<br /> operator()(const _Tp& __x, const _Tp& __y) const<br /> { return strcmp( __x, __y ) == 0; }<br />};<br />// 定義雜湊表時,用如下方法(這次不能跳過第三個模板參數,所以要指定):<br />__gnu_cxx::hash_map< char*, int, __gnu_cxx::hash<char*>, my_equal_to<char*> > myHash;<br />
3>
遍曆__gnu_cxx::hash_map出現了死迴圈,這個問題並不常見,然而遇到了可能真讓人摸不到頭腦。還好我之前見過這篇文章,沒有在這裡陷很久。
http://blog.csdn.net/tototony/article/details/5689882
這個問題簡單說來,就是gnu的實現是,內部有個_M_Cur指標指示當前位置A,每次計算operator++,都用當前位置的key調用hashFunction Compute下一個位置B,如果key傳入hash_map以後,又在外部將其內容破壞,導致hashFunction Compute後的B位置在A位置之前,那麼從B到達A以後,又會跳回B,形成B-A區間的死迴圈。