[英]C++ Aware duplication insert into a std::map
我有一個關於在C ++中向std :: map插入內容的問題。
多數民眾贊成在我的代碼沙發:
stringutils.hh:
...
unsigned long hashSDBM(char *strToHash){
unsigned char* str = new unsigned char[strlen(strToHash) + 1];
strncpy( (char *) str, strToHash, strlen(strToHash) );
unsigned long hash = 0;
int c;
while ((c = *str++)){
hash = c + (hash <<6) + (hash <<16) - hash;
}
return hash;
}
...
哈希圖
#include "stringutils.hh"
namespace{
using namespace std;
class MapElement{
private:
char* filename;
char* path;
public:
MapElement(char* f, char* p):filename(f), path(p){}
~MapElement(){
delete [] filename;
delete [] path;
}
char* getFileName(){ return filename; }
char* getPath(){ return path; }
};
class HashMap{
private:
map<long*, MapElement*> *hm;
long hash(char* key);
public:
HashMap(){
hm = new map<long*, MapElement*>();
}
~HashMap(){
delete hm;
}
long put(char* k, MapElement *v);
};
long HashMap::hash(char* key){
return stringutils::hashSDBM(key);
}
long HashMap::put(char* k, MapElement *v){
long *key = new long();
*key = hash(k);
pair<map<long*,MapElement*>::iterator, bool> ret;
ret = hm->insert(std::pair<long*, MapElement*>(key, v));
if(ret.second == false){
cerr<<"Already exists: "<<ret.first->second->getFileName()<<endl;
return *key;
}
cerr<<"INSERTED "<<*key<<endl;
return 0;
}
main.cc:
HashMap *hm = new HashMap();
int main(void){
MapElement *m1;
char a[] = "hello";
char b[] = "world";
m1 = new MapElement(a,b);
hm->put(a, m1);
char c[] = "thats";
char d[] = "a test";
m1 = new MapElement(c,d);
hm->put(c, m1);
char e[] = "hello";
char f[] = "test";
m1 = new MapElement(e,f);
hm->put(e, m1);
return 0;
}
它會編譯出所有錯誤或警告,當我啟動它時,將生成以下輸出:
插入的7416051667693574450
插入8269306963433084652
插入的7416051667693574450
為什么第二個插入鍵“ hello”沒有作用?
std::map
中的鍵是唯一的。 如果要允許重復的鍵,請使用std::multimap
。 您正在使用的map :: insert返回一對迭代器和一個bool
。 布爾值指示插入是否已實際插入(如果密鑰已經在其中,則不會)。
為什么第二次插入鍵沒有任何作用?
您的鍵是一個指針,指向具有相同值的不同long
對象的兩個指針是不同的鍵。 您可以通過不過度使用指針來真正幫助自己。 C ++不是Java。
好的...請先閱讀一本好書,然后再繼續閱讀,C ++標記說明中推薦了一些好書。
因此,這里的問題是您的代碼在所有地方都使用了指針……並且指針的行為不像您認為的那樣。 諸如Java之類的許多語言都有普遍的引用類型:所有內容都只是一個引用。 C ++不是這種語言,它一方面使指針/引用與另一方面使值產生很大差異。
在您的特定情況下, long*
是指向long
的指針。 就map
而言,兩個不同的指針僅代表它們: distant ,無論它們指向的值如何。
所以...我們需要擺脫那些指針。 到處。 並停止在C ++中使用C習慣用法。
stringutils.hh
unsigned long hashSDBM(std::string const& strToHash){
unsigned long hash = 0;
for (char c: strToHash) {
hash = c + (hash <<6) + (hash <<16) - hash;
}
return hash;
}
簡而言之:
char*
,內存所有權尚不清楚,這會導致泄漏/懸空指針 const
,不修改其參數的函數應采用const
引用它們 哈希圖
namespace HashMap {
class MapElement{
public:
MapElement(std::string f, std::string p):
filename(f), path(p) {}
std::string const& getFileName() const { return filename; }
std::string const& getPath() const { return path; }
private:
std::string filename;
std::string path;
};
讓我們從這里開始:
向前:
class HashMap{
public:
unsigned long put(std::string const& k, MapElement v);
private:
static unsigned long hash(std::string const& key);
std::map<unsigned long, MapElement> hm;
};
inline unsigned long HashMap::hash(std::string const& key){
return stringutils::hashSDBM(key);
}
inline unsigned long HashMap::put(std::string const& k, MapElement v){
unsigned long const key = hash(k);
auto const ret = hm.emplace(key, v);
if (ret.second == false){
std:: cerr << "Already exists: " << ret.first->second.getFileName() << "\n";
return key;
}
std::cerr << "INSERTED " << key << "\n";
return 0;
}
好的...
hash
函數不訪問任何狀態,使其變為static
auto
而不是顯式命名過於復雜的類型 std::endl
不會執行您認為的操作(提示:它將刷新緩沖區!最慢的I / O操作!),只需使用普通的"\\n"
進一步說明:
MapElement
對象中讀取它...或在發生沖突時打印key
(而不是文件名),以防它們不同 0
,而在插入時返回key
...但是沒有什么阻止該鍵為0
因此接收到0
會使用戶懷疑發生了什么 main.cpp
int main(void){
HashMap::HashMap hm;
hm.put("hello", MapElement("hello", "world"));
hm.put("thats", MapElement("thats", "a test"));
hm.put("hello", MapElement("hello", "test"));
return 0;
}
最后:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.