【发布时间】:2013-10-14 19:19:51
【问题描述】:
我在 C++ 中实现了一个哈希映射,以便了解更多关于一般关联映射的信息,除了一个症结之外,一切都运行良好——我希望程序员能够创建具有任意参数化的映射(例如 [使用 @987654321 @例如]HashMap<string,string*>、HashMap<string,string>、HashMap<string*,string>等都是合法的)。
问题在于,在HashMap::get(int key_data) 函数中,如果我支持将对象作为映射值,则在未命中(给定键与任何映射值不匹配的情况下)返回的映射值不能简单地为NULL。我可以让get(...) 函数始终返回一个指向参数化映射值类型的指针,但如果该类型已经是一个指针,我不能使用一元 & 运算符,如果它是一个对象,我必须使用& 运营商。我肯定不想用RTTI,所以问题如下:
如何从我的 HashMap::get() 函数中同时允许对象和指向对象的返回类型,这也是允许未命中所必需的?
请记住,我使用的是 gcc 4.7 并打开了 C++11,因此所有 C++11 功能和注意事项都适用。下面遵循我的HashMap::get() 函数到目前为止使用“始终返回指向任何 value_data 恰好是的指针”范例:
template <class key_data,class value_data> value_data*
HashMap<key_data,value_data>::get(key_data dk) {
int key = keyGen(dk);
int hash_val = HashFunc(key);
HashNode* entry = _table[hash_val];
while (entry != 0) {
if (entry->getCurrentKey() == key) {
//value_data val = entry->getCurrentValue(); //this temporary will be
//gone from the stack quickly and therefore the returned pointer to a
//pointer (if value_data is a pointer) will segfault
return &(entry->getCurrentValue()); //this should be legal and yield
//a pointer to a pointer (iff value_data was a pointer), but instead
//I get a compiler error claiming
//operator & requires an lvalue operand...
}
entry = entry->next();
}
printf("Your get of int key %i resulted in no hits."
"The returned pointer to Value is NULL!\n",key);
return NULL;
}
正如 cmets 所述,return &(entry->getCurrentValue()); 行引发编译器错误,指出运算符 & 需要左值操作数。我可以通过将value_data 临时放到堆栈上来消除该错误,但是当我实际尝试使用它时会导致段错误,因为返回的指针几乎会立即无效。简单地使用引用来抽象出语法问题也不起作用,因为在这种情况下,无法通过 return NULL 实现未命中(ISO 要求引用与原始指针不同,指向有效的左值)。
如果有人对处理可能“无效”的返回引用有任何建议(例如可以查询其他所有内容继承自其有效性的虚拟对象),我也愿意接受。
【问题讨论】:
-
为什么不看看标准库是如何解决这个问题的?
-
“我得到一个编译器错误,声称运算符 & 需要一个左值操作数...”我敢打赌
getCurrentValue按值(或指针)返回?如果是这样,它返回一个纯右值。为了让它编译,让它返回一个引用。 (不过,这并不能解决根本问题。) -
getCurrentValue() 返回任何 value_data 参数化的值;可以是对象或指针(我不支持引用,因为它们不容易允许上面定义的“未命中”)
-
@CCJ 在您的示例中,
getCurrentValue仅在条目存在时才被调用,对吧?所以它可以返回一个引用。 -
@CCJ 如果您使用
operator[]并且找不到密钥,则标准库关联容器会通过 default-ctor 创建一个新值。在任何情况下,都会返回一个有效的引用。这允许my_map[key] = something;无论元素是否事先存在。您可以使用at成员函数(或find)进行“边界检查”。
标签: c++ pointers c++11 reference hashmap