【问题标题】:Why can't I pass const map structure to a function in c++?为什么我不能将 const map 结构传递给 C++ 中的函数?
【发布时间】:2010-05-02 05:37:04
【问题描述】:

我尝试用向量传递 const,它可以工作: 例如:

void damn(const vector <bool> &bb)
{
    for (int i=0; i<bb.size(); i++)
        cout<<bb[i]<<endl;

}

但是在尝试使用地图时,它没有:

void pas(const map <string, float> &mm)
{
    cout<<mm["a"];
    cout<<mm["b"];
}

我想知道为什么没有。

【问题讨论】:

  • 以什么方式失败?你能通过从函数体中删除行来编译它吗,因为参数看起来是正确的。
  • 编译器非常清楚出了什么问题:const-map.cpp:9: error: passing ‘const std::map&lt;std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, float, std::less&lt;std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt; &gt;, std::allocator&lt;std::pair&lt;const std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, float&gt; &gt; &gt;’ as ‘this’ argument of ‘_Tp&amp; std::map&lt;_Key, _Tp, _Compare, _Alloc&gt;::operator[](const _Key&amp;) [with _Key = std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, _Tp = float, _Compare = std::less&lt;... Duh。
  • 可怕的错误 :),尽管 Potatoswatter 在下面有正确的答案 - 你不能在 const 地图上调用 operator[]。
  • @Joey:有时如果错误消息不那么丰富会很好。 :-)

标签: c++ map constants


【解决方案1】:

map::operator[] 有点奇怪。它这样做:

  1. 寻找钥匙。
  2. 如果找到,请退回。
  3. 如果没有,插入它并默认构造它的关联值。
  4. 然后返回对新值的引用。

第 3 步与constness 不兼容。该语言没有两个功能不同的 operator[] 重载,而是强制您将 map::find 用于 const 对象。

或者,有人可能会争论,如果争论不在地图中,map::operator[] const 会做什么?抛出异常?未定义的行为? (毕竟,这就是vector::operator[] 对越界索引所做的事情。)无论如何,我们避免了这个问题,只是给我们带来了一点不便。

如果找不到keymy_map.find(key) 将返回my_map.end()

【讨论】:

  • 为了公平对待标准库 - o​​perator[] const 的行为如何?如果元素不存在,它会做什么?让它抛出异常会令人困惑,因为其他标准容器都没有这种行为。在我看来,他们应该通过将非常量运算符 [] 排除在外来解决这个问题,但这只是我的意见。
  • @Stewart:最统一的语法和语义将通过颠倒vector::atvector::operator[] 的角色,并定义map::operator[] const 来抛出。但这会对性能造成太大影响。鉴于此页面上建议执行 cout&lt;&lt;my_map.find(key)-&gt;second;,我目前支持异常解决方案。尽管它们可能令人惊讶,但至少它们在弹出时提供了丰富的信息。
  • @Potatoswatter:我明白你的意思,但他们不能改变向量的 operator[] 语义,因为这会使它与数组不兼容。我个人从未使用过vector::at,也从未见过有人使用它——我总是确保我知道我的职位何时有效。交换角色意味着我必须在任何地方使用 at() ,就像我见过的任何使用向量的代码一样。
  • @Stewart:访问越界索引不是兼容性所需的功能。 at()[] 对于有效索引是可互换的,所以我不明白你的意思。关键的区别在于性能。实际上,要真的使vectormap 匹配,越界向量下标应该调用resize。 Java不是那样做的吗?无论如何,这是一个毫无意义的争论,因为 C++ 旨在以简单为代价实现高性能。
  • @Potatoswatter - 我不是在争论 - 只是享受辩论:)。对我来说,我使用 C++ 进行操作系统开发,如果 std::vector 没有表现出它的行为方式,我们仍然会使用 C 进行几乎所有的事情。这是我们开始认真使用的第一个“正确”的 C++ 东西之一,并为更多的东西打开了大门——范围检查将是老派 C 人不允许的性能打击。我不了解 Java,但我知道 C# 总是进行范围检查。这是迭代性能更高的原因之一。
【解决方案2】:

std::map::operator[] 如果请求的元素不在地图中,则插入默认构造的元素。这是why it is not a const member function。您可以改用std::map::find,但一定要检查它返回的迭代器。

【讨论】:

    【解决方案3】:

    我相信这是因为地图中的[] 不是const,因为如果您寻址到不存在的一对,它会创建具有默认值的新对。试试

    void pas(const map <string, float> &mm)
    {
        cout<<mm.find("a")->second;
        cout<<mm.find("b")->second;
    }
    

    【讨论】:

    • 使 cout &lt;&lt; mm.find("a")-&gt;second,因为 mm.find("a") 返回一个指向 std::pair 的迭代器。
    • 请注意,如果找不到密钥,此类代码可能会崩溃。
    • 如果这样做,您必须检查返回的迭代器 - 如果元素不存在,find 将返回 map::end(),并取消引用 map::end()是未定义的行为。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-28
    • 1970-01-01
    • 2014-05-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多