我何时应该使用std :: map :: at检索地图元素

我已经阅读了有关Web的不同文章以及关于stackoverflow的问题,但是对我来说,尚不清楚是否有任何例外情况可以更好地使用map::operator[]检索地图元素。

根据定义map::operator[]

返回对以标识的元素的映射值的引用 密钥k。

如果k与容器中任何元素的键都不匹配,则 函数抛出out_of_range异常。

对我来说,只有当您100%确保存在具有特定键的元素时,才值得使用map::operator[],否则,您应该考虑异常处理。

  1. 在什么情况下map::operator[]被认为是最有效,最优雅的方法? 在哪种情况下,您建议使用map::find()
  2. 我有可能在没有这样的键的情况下使用map::operator[]更好吗? 而map::find()它是更快,更优雅的方法吗?
map::operator[]

map::operator[]有时可能很危险,因为如果不存在某个元素,它将插入该元素。

编辑:链接以某种方式相关的链接1链接2链接3链接4链接5链接6

T M asked 2020-06-30T00:49:46Z
8个解决方案
63 votes

与这里现有的大多数答案相反,请注意,实际上有4种方法与在地图中查找元素有关(忽略了operator[]insertemplace,它们不太精确):

  • operator[]仅存在于非const版本中,如前所述,如果不存在,它将创建元素
  • 在C ++ 11中引入的operator[],返回对该元素的引用(如果存在),否则抛出异常
  • operator[]将迭代器返回到元素(如果存在),或者将迭代器返回到insert(如果不存在)
  • operator[]返回此类元素的数量,在insert中,该值为0或1

现在语义已经很清楚了,让我们回顾一下什么时候使用:

  • 如果您仅想知道operator[]中是否存在某个元素,请使用insert
  • 如果您希望访问该元素,并且该元素应位于operator[]中,请使用insert
  • 如果您希望访问该元素,并且不知道它是否在operator[]中,请使用insert; 不要忘记检查生成的迭代器是否等于emplace的结果。
  • 最后,如果您希望访问该元素(如果存在)或创建(然后访问)它(如果不存在),请使用operator[]; 如果您不想调用类型默认构造函数来创建它,则可以适当使用insertemplace
Matthieu M. answered 2020-06-30T00:50:37Z
21 votes

如果找不到元素,则map::find()会引发std::logic_error异常。 从使用的角度来看,此异常是logic_error的一种异常,对我而言,它是assert()的一种同义词:应将其用于报告程序内部逻辑中的错误,例如违反逻辑先决条件或类不变式。

另外,您可以使用map::find()访问const映射。

因此,对于您的问题:

  1. 当访问常量映射并且元素缺失是逻辑错误时,我建议使用map::find()而不是std::logic_error
  2. 是的,当您不确定元素是否在此处时,最好使用map::find():在这种情况下,这不是逻辑错误,因此即使我们不考虑性能,抛出并捕获std::logic_error异常也不是一种非常优雅的编程方式 。
alexeykuzmin0 answered 2020-06-30T00:51:16Z
12 votes

如您所述,有三种不同的方式来访问地图中的元素:find()at()find()(也有upper_boundlower_boundequal_range,但这些方法用于更复杂的情况下,您可能希望找到下一个/上一个元素等。 )

那么,什么时候应该使用哪个呢?

find()基本上是“如果不存在,则使用默认构造的映射元素创建一个”。 这意味着它不会抛出(除非在特殊情况下抛出内存分配,或者抛出键或值构造函数之一),并且您肯定会获得对所寻找元素的引用-现有元素还是新创建的元素 。

如果该键没有任何元素,则抛出find()。 由于您不应在正常程序流程中使用异常,因此使用at()会说“我确定有这样一个元素”。 但是,如果您错了,还有一个额外的好处,那就是您可以得到一个异常(而不是未定义的行为)。 如果您不确定该元素是否存在,请不要使用它。

find()说:“也许有,也可能没有。”让您有可能对这两种情况做出不同的反应。 因此,这是更通用的方法。

Arne Mertz answered 2020-06-30T00:51:56Z
5 votes

op[]0words[word]++;中的所有3个都是有用的。

  • op[]如果您不想意外插入元素,而仅在元素存在时才采取行动,则很好。

  • op[]很好,如果您希望地图上应该有东西,并且无论如何都不会抛出异常。 与words[word]++;(不能使用op[])相比,它还可以更简洁地访问0地图。

  • op[]如果您想插入一个默认元素(例如,对于单词计数程序,它会为首次遇到的每个单词都放入一个int 0)(使用成语words[word]++;)是个好方法。

Bartek Banachewicz answered 2020-06-30T00:52:30Z
3 votes

这取决于此功能的要求以及您如何构造项目。 如果您应该返回一个对象,但由于找不到该对象而无法返回,那么它将为您提供两种处理方式的选择。 您可能会遇到异常,也可能会返回某种哨兵,这意味着什么也没发现。 如果要抛出异常,请使用at(),因为异常将为您抛出。 如果您不想引发异常,请使用find(),这样您就不必为了返回哨兵对象而处理异常。

NathanOliver answered 2020-06-30T00:52:51Z
3 votes

我认为,这取决于您的用例。 std::map::at()的返回类型是对找到的元素的值的左值引用,而std::map::find()返回一个迭代器。 您可能更喜欢

return myMap.at("asdf"s) + 42;

在更详尽的表达中

return myMap.find("asdf"s)->second + 42;

每当在表达式中使用std::map::at()的结果时,您都希望该元素存在,并将缺失的元素视为错误。 因此,例外是处理该问题的好选择。

cdonat answered 2020-06-30T00:53:20Z
2 votes

我想区别是语义。

find()在我的机器上看起来像这样:

mapped_type&
at(const key_type& __k)
{
    iterator __i = lower_bound(__k);
    if (__i == end() || key_comp()(__k, (*__i).first))
        __throw_out_of_range(__N("map::at"));
    return (*__i).second;
}

如您所见,它使用find(),然后检查find(),比较键,并在需要的地方引发异常。

find()看起来像这样:

iterator
find(const key_type& __x)
{ return _M_t.find(__x); }

其中find()是一棵存储实际数据的红黑树。 显然,这两个函数具有相同的(对数)复杂度。 当您使用find() +检查end()时,您所做的几乎与at相同。 我会说语义上的区别是:

  • 当您需要在特定位置放置元素并且您认为该元素在其中时,请使用find()。 在这种情况下,所需位置缺少元素的情况非常特殊,因此find()引发异常。
  • 需要在地图上查找元素时,请使用find()。 在这种情况下,元素不存在的情况是正常的。 还要注意,find()返回一个迭代器,您可以将其用于除简单获取其值之外的目的。
SingerOfTheFall answered 2020-06-30T00:54:07Z
2 votes

map :: at()返回一个左值引用,当您按引用返回时,您可以使用其所有可用的好处,例如方法链接。

例:

  map<int,typ> table;
  table[98]=a;
  table[99]=b;

  table.at(98)=table.at(99);

operator[]还通过引用返回映射的值,但是如果未找到要搜索的键,则可能会插入一个值,在这种情况下,容器大小将增加一。

这需要您格外小心,因为您必须注意迭代器无效。

我说对了,最好在有地图时使用map :: find() 可能没有这样的钥匙元素? 和map :: find()它是 更快更优雅的方法?

是的,从语义上讲,当您不确定元素的存在时使用find()是有意义的,即使是新手也可以使代码更易于理解。

至于时间效率,通常将映射实现为RB树/一些平衡的二进制搜索树,因此,find()的复杂度为O(logN)。

C ++规范:

T&运算符[](const key_type&x);
效果:如果在映射中没有等效于x的键,则将value_type(x,T())插入到映射中。 要求:key_type必须为CopyInsertable,而mapping_type必须为 DefaultInsertable插入* this。 返回:对 * this中对应于x的appedd_type。 4复杂度:对数。

T&at(const key_type&x);
const T&at(const key_type&x)const; 返回:对与* this中的x对应的mapping_type的引用。 抛出:如果不存在此类元素,则为out_of_range类型的异常对象。 复杂度:对数。

basav answered 2020-06-30T00:55:17Z
translate from https://stackoverflow.com:/questions/33236038/when-i-should-use-stdmapat-to-retrieve-map-element