C++ 当我应该使用 std::map::at 来检索地图元素时
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33236038/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When I should use std::map::at to retrieve map element
提问by T M
I have read different articles on web and questions at stackoverflow, but for me it is not clear is there any exclusive case when it is better to use std::map::at
to retrieve map element.
我已经阅读了网络上的不同文章和stackoverflow上的问题,但对我而言,尚不清楚是否有更好的使用std::map::at
来检索地图元素的排他性案例。
According to definition, std::map::at
根据定义,std::map::at
Returns a reference to the mapped value of the element identified with key k.
If k does not match the key of any element in the container, the function throws an out_of_range exception.
返回对使用键 k 标识的元素的映射值的引用。
如果 k 与容器中任何元素的键都不匹配,则该函数会抛出 out_of_range 异常。
For me only case when it is worth to use std::map::at
when you 100% sure that element with particular key exist, otherwise you should consider exception handling.
对我而言,只有std::map::at
当您 100% 确定具有特定键的元素存在时才值得使用,否则您应该考虑异常处理。
- Is there any case where
std::map::at
considered as most efficient and elegant way to do? In what cases you will recommend to usestd::map::at
? - Am I right that it is better to use
map::find()
when there is a possibility to not have element with such a key? Andmap::find()
it is faster and more elegant approach?
- 是否有任何情况
std::map::at
被认为是最有效和最优雅的方式?在什么情况下你会推荐使用std::map::at
? map::find()
当有可能没有带有这样一个键的元素时,最好使用我是对的吗?并且map::find()
它更快,更好的方法?
if ( map.find("key") != map.end() ) { // found } else { // not found }
if ( map.find("key") != map.end() ) { // found } else { // not found }
p.s
ps
map::operator[]
sometimes can be dangerous, because if an element doesn't exist then it will inserts it.
map::operator[]
有时可能很危险,因为如果一个元素不存在,那么它会插入它。
EDITED:links somehow related link 1link 2link 3link 4link 5link 6
回答by Matthieu M.
Contrary to most existing answers here, note that there are actually 4methods related to finding an element in a map (ignoring lower_bound
, upper_bound
and equal_range
, which are less precise):
与此处大多数现有答案相反,请注意,实际上有4种与在地图中查找元素相关的方法(忽略不太精确的lower_bound
、upper_bound
和equal_range
):
operator[]
only exist in non-const version, as noted it will create the element if it does not existat()
, introduced in C++11, returns a reference to the element if it exists and throws an exception otherwisefind()
returns an iterator to the element if it exists or an iterator tomap::end()
if it does notcount()
returns the number of such elements, in amap
, this is 0 or 1
operator[]
仅存在于非常量版本中,如前所述,如果元素不存在,它将创建该元素at()
,在 C++11 中引入,如果元素存在则返回对元素的引用,否则抛出异常find()
如果元素存在则返回一个迭代器,map::end()
如果它不存在则返回一个迭代器count()
返回此类元素的数量,在 a 中map
,这是 0 或 1
Now that the semantics are clear, let us review when to use which:
现在语义已经清楚了,让我们回顾一下何时使用 which:
- if you only wish to know whether an element is present in the
map
(or not), then usecount()
. - if you wish to access the element, and it shall be in the
map
, then useat()
. - if you wish to access the element, and do not know whether it is in the
map
or not, then usefind()
; do not forget to check that the resulting iterator is not equal to the result ofend()
. - finally, if you wish to access the element if it exists or create it (and access it) if it does not, use
operator[]
; if you do not wish to call the type default constructor to create it, then use eitherinsert
oremplace
appropriately
- 如果您只想知道元素是否存在于
map
(或不存在)中,则使用count()
. - 如果您希望访问该元素,并且它应在 中
map
,则使用at()
. - 如果您想访问该元素,并且不知道它是否在该元素中
map
,则使用find()
; 不要忘记检查结果迭代器是否不等于 的结果end()
。 - 最后,如果您希望访问该元素(如果它存在)或创建它(并访问它)如果它不存在,请使用
operator[]
; 如果您不想调用类型默认构造函数来创建它,则使用insert
或emplace
适当地使用
回答by alexeykuzmin0
std::map::at()
throws an out_of_range
exception if the element could not be found. This exception is a kind of logic_error
exception which for me is a kind of synonym of assert()
from the usage standpoint: it should be used to report errors in the internal logic of the program, like violation of logical preconditions or class invariants.
std::map::at()
out_of_range
如果找不到元素,则抛出异常。这个异常是一种logic_error
异常,assert()
从使用的角度来看,它对我来说是一种同义词:它应该用于报告程序内部逻辑中的错误,例如违反逻辑前提或类不变量。
Also, you can use at()
to access const maps.
此外,您可以使用at()
来访问常量映射。
So, for your questions:
所以,对于你的问题:
- I will recommend using
at()
instead of[]
when accessing const maps and when element absence is a logic error. - Yes, it's better to use
map::find()
when you're not sure element is here: in this case it's not a logic error and so throwing and catchingstd::logic_error
exception will not be very elegant way of programming, even if we don't think about performance.
- 当访问 const 映射以及元素缺失是逻辑错误时,我将推荐使用
at()
代替[]
。 - 是的,
map::find()
当您不确定元素是否在这里时最好使用:在这种情况下,它不是逻辑错误,因此std::logic_error
即使我们不考虑性能,抛出和捕获异常也不是非常优雅的编程方式。
回答by Arne Mertz
As you noted, there are three different ways to access elements in a map: at()
, operator[]
and find()
(there are also upper_bound
, lower_bound
and equal_range
, but those are for more complicated circumstances where you might want to find a next/previous element etc.)
正如您所指出的,有三种不同的方法可以访问地图中的元素:at()
,operator[]
和find()
(还有upper_bound
,lower_bound
和equal_range
,但这些适用于更复杂的情况,您可能想要找到下一个/上一个元素等)
So, when should you use which one?
那么,什么时候应该使用哪一种呢?
operator[]
is basically "if it does not exist, create one with a default-constructed mapped element". That means it won't throw (except in the corner cases when the memory allocation throws or one of the key or value constructors throw), and you definitely get a reference to the element you looked for - either the existing one or the newly created.
operator[]
基本上是“如果它不存在,则使用默认构造的映射元素创建一个”。这意味着它不会抛出(除非在内存分配抛出或键或值构造函数之一抛出的极端情况下),并且您肯定会获得对您查找的元素的引用 - 现有元素或新创建的元素.
at()
throws if there is no element for that key. Since you should not use exceptions for normal program flow, using at()
is saying "I am sure there is such an element." But with the added benefit that you get an exception (and not undefined behavior) if you are wrong. Don't use this if you are not positive that the element exists.
at()
如果该键没有元素,则抛出。由于您不应该对正常程序流使用异常,因此 usingat()
是说“我确定存在这样的元素”。但是如果你错了,你会得到一个例外(而不是未定义的行为)。如果您不确定该元素是否存在,请不要使用它。
find()
says "there may or may not be such an element, let's see..." and offers you the possibility to react to both cases differently. It therefore is the more general approach.
find()
说“可能有也可能没有这样的元素,让我们看看......”并为您提供对两种情况做出不同反应的可能性。因此,它是更通用的方法。
回答by Bartek Banachewicz
All 3 of find
, operator[]
and at
are useful.
所有3 find
,operator[]
和at
是有用的。
find
is good if you don't want to accidentally insert elements, but merely act if they exist.at
is good if you expect that something should be on a map and you'd throw an exception if it wasn't anyway. It can also accessconst
maps in a more concise matter thanfind
(where you can't useop[]
)op[]
is good if you wantto insert a default element, such as for the word counting program which puts an int0
for every word encountered for the first time (with the idiomwords[word]++;
).
find
如果您不想意外插入元素,但只是在它们存在时才采取行动,这很好。at
如果您期望地图上应该有某些东西,并且无论如何都不会抛出异常,那么这很好。它还可以const
以比find
(您不能使用的地方op[]
)更简洁的方式访问地图op[]
如果您想插入一个默认元素,例如单词计数程序,它0
会为第一次遇到的每个单词放置一个 int (使用 idiomwords[word]++;
),这是很好的。
回答by cdonat
I think, it depends on your usecase. The return type of std::map::at()
is an lvalue reference to the value of the found element, while std::map::find()
returns an iterator. You might prefer
我认为,这取决于您的用例。的返回类型std::map::at()
是对找到的元素值的左值引用,同时std::map::find()
返回一个迭代器。你可能更喜欢
return myMap.at("asdf"s) + 42;
in expressions over the more elaborate
在表达上更精细
return myMap.find("asdf"s)->second + 42;
Whenever you use the result of std::map::at()
in an expression, you expect the element to exist, and regard a missing element as an error. So an exception is a good choice to handle that.
每当您std::map::at()
在表达式中使用结果时,您都希望该元素存在,并将缺失的元素视为错误。因此,异常是处理该问题的不错选择。
回答by NathanOliver
This depends on what the requirements are for this function and how you are structuring the project. If you are supposed to return an object and you can't because it was not found then it leaves you with two options on how to handle that. You could through an exception or you could return some sort of sentinel that means nothing was found. If you want to throw an exception then use at()
as the exception will be thrown for you. If you do not want to throw an exception then use find()
so you do not have to deal with handling an exception just to return a sentinel object.
这取决于此功能的要求以及您如何构建项目。如果您应该返回一个对象,但由于未找到它而不能返回,那么它为您提供了两个关于如何处理该对象的选项。您可以通过异常,也可以返回某种表示未找到任何内容的哨兵。如果你想抛出一个异常,那么 useat()
因为将为你抛出异常。如果您不想抛出异常,请使用,find()
这样您就不必为了返回一个哨兵对象而处理异常。
回答by SingerOfTheFall
I guess the difference is semantics.
我想区别在于语义。
std::map::at()
looks like this on my machine:
std::map::at()
在我的机器上看起来像这样:
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;
}
As you can see, it uses lower_bound
, then checks for end()
, compares keys, and throws the exception where needed.
如您所见,它使用lower_bound
,然后检查end()
,比较键,并在需要的地方抛出异常。
find()
looks like this:
find()
看起来像这样:
iterator
find(const key_type& __x)
{ return _M_t.find(__x); }
where _M_t
is a red-black tree that stores the actual data. Obviously, both function have the same (logarithmic) complexity. When you use find()
+ check for end()
, you are doing almost the same thing that at
does. I would say the semantic difference is:
其中_M_t
是存储实际数据的红黑树。显然,这两个函数具有相同的(对数)复杂度。当您使用find()
+ check for 时end()
,您正在做几乎相同的事情at
。我会说语义差异是:
- use
at()
when you need an element at a specific location, and you assume that it is there. In this case, the situation of the element missing from the desired place is exceptional, thusat()
throws an exception. - use
find()
when you need to find the element in the map. In this case the situation when the element is not present is normal. Also note thatfind()
returns an iterator which you may use for purposes other than simply obtaining it's value.
- 使用
at()
当你在一个特定位置需要的元素,你认为它的存在。在这种情况下,元素缺少所需位置的情况是异常的,因此at()
会抛出异常。 - 使用
find()
时,你需要找到在地图的元素。在这种情况下,元素不存在的情况是正常的。另请注意,find()
返回一个迭代器,您可以将其用于简单获取其值以外的目的。
回答by basav
map::at() returns a l-value reference, and when you return by reference, you can use all its available benefits such as method chaining.
map::at() 返回一个左值引用,当您通过引用返回时,您可以使用其所有可用的好处,例如方法链。
example:
例子:
map<int,typ> table;
table[98]=a;
table[99]=b;
table.at(98)=table.at(99);
operator[]
also returns the mapped value by reference, but it may insert a value if searched for key is not found, in which case container size increases by one.
operator[]
还通过引用返回映射的值,但如果未找到搜索的键,它可能会插入一个值,在这种情况下,容器大小增加 1。
This requires you to be extra cautious since you have to take care of iterator invalidation.
这需要您格外小心,因为您必须处理迭代器失效问题。
Am I right that it is better to use map::find() when there is a possibility to not have element with such a key? And map::find() it is faster and more elegant approach?
当有可能没有具有此类键的元素时,最好使用 map::find() 是否正确?而 map::find() 是更快更优雅的方法吗?
Yes, semantically it makes sense to use find() when you are not sure of the existence of element.Makes the code easier to understand even for a newbie.
是的,从语义上讲,当您不确定元素是否存在时,使用 find() 是有意义的。即使对于新手,也使代码更容易理解。
As for the time efficiency, map is generally implemented as a RB-tree/some balanced binary search tree and hence, complexity is O(logN) for find().
至于时间效率,map通常被实现为一个RB树/一些平衡的二叉搜索树,因此,find()的复杂度是O(logN)。
C++ Spec:
T& operator[](const key_type& x);
Effects: If there is no key equivalent to x in the map, inserts value_type(x, T()) into the map. Requires: key_type shall be CopyInsertable and mapped_type shall be DefaultInsertable into *this. Returns: A reference to the mapped_type corresponding to x in *this. 4 Complexity: Logarithmic.T& at(const key_type& x);
const T& at(const key_type& x) const; Returns: A reference to the mapped_type corresponding to x in *this. Throws: An exception object of type out_of_range if no such element present. Complexity: Logarithmic.
C++ 规范:
T& operator[](const key_type& x);
效果:如果映射中没有与 x 等效的键,则将 value_type(x, T()) 插入映射中。要求:key_type 应为 CopyInsertable,mapped_type 应为 DefaultInsertable into *this。返回: 对与 *this 中的 x 对应的映射类型的引用。4 复杂度:对数。T& at(const key_type& x);
const T& at(const key_type& x) const; 返回: 对与 *this 中的 x 对应的映射类型的引用。抛出:如果不存在此类元素,则为 out_of_range 类型的异常对象。复杂度:对数。