我有一个关于在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;
}
...
hashmap.hh
#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;
}
它会编译出任何错误或警告,当我启动它时,以下输出是generatéd:
INSERTED 7416051667693574450
INSERTED 8269306963433084652
INSERTED 7416051667693574450
为什么第二次插入关键字“你好”没有任何影响?
答案 0 :(得分:2)
std::map
中的密钥是唯一的。如果您想允许重复密钥,请使用std::multimap
。你正在使用的map :: insert返回一对迭代器和一个bool
。 bool表示插入是否实际插入(如果密钥已经存在,则表示插入)。
答案 1 :(得分:1)
为什么键的第二个插入没有任何效果?
您的密钥是一个指针,指向具有相同值的不同long
个对象的两个指针是不同的密钥。如果不过度使用指针,你真的会帮助自己。 C ++不是Java。
答案 2 :(得分:0)
天哪......在继续学习之前,请先阅读一本好的C ++书籍,C ++标签说明中推荐了好书。
所以,这里的问题是你的代码使用指针......无处不在......指针的行为与你认为的不同。许多语言(如Java)都具有普遍的引用类型:一切都只是一个引用。 C ++不是这样一种语言,它一方面指针/引用与另一方面的值之间存在很大差异。
在您的具体情况下,long*
是指向long
的指针。就map
而言,两个不同的指针就是: distinct ,无论它们指向的是什么价值。
所以......我们需要摆脱那些指针。到处。并停止在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
引用它们hashmap.hh
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
,而在{... 1}}时却没有...但是没有任何内容可以阻止密钥key
,因此接收0
会让用户怀疑发生了什么的main.cpp
0
结束: