无序地图 - 使用const键

时间:2016-12-08 22:40:27

标签: c++ unordered-map

我有一个无序映射,它使用指向自定义对象的指针作为键。 出于某种原因,只有在键不是const的情况下才能使用键查找值。

以下是一个示例(std::string作为自定义对象的替身):

std::unordered_map<std::string*, int> my_map;

std::string key {"test"};
const std::string const_key {"test2"};

auto value = my_map.at(&key);  // this works as expected
auto other_value = my_map.at(&const_key);  // this doesn't compile


error: invalid conversion from 'const string* {aka const std::__cxx11::basic_string<char>*}' 
to 'std::unordered_map<std::__cxx11::basic_string<char>*, int>::key_type 
{aka std::__cxx11::basic_string<char>*}' [-fpermissive]

为什么查找要求指针为非const?

3 个答案:

答案 0 :(得分:5)

当您撰写 $(document).ready(function () { //look for some kind of click below $(document).on('click', '#InsertDefault', function (event) { $.ajax({ url: "/backend.phps", type: 'POST', cache: false, data: {act: 'default'}, dataType: 'json', success: function (output, text, error) { for (var key in output.defaultData) { document.getElementById(key).value = data[key] } }, error: function (jqXHR, textStatus, errorThrown) { //Error handling for potential issues. alert(textStatus + errorThrown + jqXHR); } }) }) preventDefault(event); }); 时,此评估结果为&const_key,但您的地图使用const std::string *作为关键字类型。

&#34;地址与字符串&#34;之间存在差异。和&#34;地址为const&#34;的字符串。因此,这些被认为是不同的类型,您不能互换使用它们。

P.S。无法将其写为评论,因此张贴为答案。

答案 1 :(得分:1)

我想提供更多关于发生这种情况的理由(我遇到了同样的问题...抱怨抱怨抱怨)。

考虑以下代码:

template <typename T>
void f(T t) { *t += 1; }

int main() {
  const int x = 0;
  //f<int*>(&x);  //error: no matching function for call to ‘f<int*>(const int*)’
  //f(&x);        //error: assignment of read-only location ‘* t’

  int y = 0;
  f<int*>(&y);   //okay, what we're "supposed" to do

  int * const z_p = &y;
  f(z_p);        //okay, we'll copy z_p by value and modify y
}

在这个(有点少)示例中,我们可以清楚地看到为什么不能将const int *作为函数f(int *)的参数。如果这样做,我们可以对其进行修改(不好)。这涵盖了no matching function call,但是在第二种情况下,我们毫无困难地完成了模板推导,但是当我们尝试修改我们的值时遇到了麻烦(这不是模板函数错误,您使用错了!)第三种情况很无聊,而且很令人期待,而我提出的第四种情况只是想提醒那些像我一样对有趣的指针类型感到困惑的人。

如果您确定所调用的函数不会改变您的内容,或者您​​是一个国际神秘主义者,那么始终可以选择投射指针。

f<int*>((int*)&x);              //that's just lazy
f<int*>(const_cast<int*>(&x));  //that's just crazy

在此特定示例中,上面代码的结果未定义。我在g++ --std=c++14 -g -O0 -Wall的机器上运行它,并达到了我的预期,x的值没有变化。今天,我们正在处理这种情况,发现由于这是未定义的行为,因此允许编译器优化从目标代码读取的const值。请注意,x仍然存在于堆栈中,您可以像其他任何操作一样修改内存中的该位置,但是当您读取它时,初始值可能仅由编译器给出。最后,如果将x的定义移到全局范围,那么如果放弃常量性并修改内存中的位置,则很可能出现段错误。

总的来说,我觉得这种混淆有些合理,因为std::unordered_map<Key,T>::value_typestd::pair<const Key, T>https://en.cppreference.com/w/cpp/container/unordered_map)。在我的脑海中,我有点想:“哦,那我只要在里面加一个const就可以了。然后,我找到了这篇文章,并想了一下上面的例子,ed了一下脑袋,然后再次发现,该语言正在保护我免受我的滑稽自我的伤害。 igh ...

有关此问题的更多阅读,请参见:https://en.cppreference.com/w/cpp/language/template_argument_deduction

答案 2 :(得分:-1)

地图声明为

std::unordered_map<std::string*, int> my_map;
                   ^^^^^^^^^^^^  

您正在使用at类型的键调用方法const std::string *

auto other_value = my_map.at(&const_key);
                             ^^^^^^^^^^

const std::string *类型到类型std::string *没有隐式转换。

您可以举例说明地图

std::unordered_map<const std::string *, int> my_map;

在这种情况下,可以使用参数std::string *const std::string *