我在网上读过不同的文章,也在stackoverflow上问过问题,但对我来说,不清楚是否有任何排他性的情况下,使用std::map::at
来检索Map元素会更好。
根据definition,std::map::at
返回一个引用,指向用键k标识的元素的Map值。
如果k与容器中任何元素的键都不匹配,函数将抛出out_of_range异常。
对于我来说,只有当你100%确定具有特定键的元素存在时,才值得使用std::map::at
,否则你应该考虑异常处理。
1.是否有任何情况下,std::map::at
被认为是最有效和优雅的方式?在什么情况下你会推荐使用std::map::at
?
1.当有可能没有带有这样一个键的元素时,我是不是更好地使用map::find()
?而map::find()
是不是更快更优雅的方法呢?
if ( map.find("key") != map.end() )
{
// found
} else
{
// not found
}
p.s
map::operator[]
有时候会很危险,因为如果一个元素不存在,它就会插入它。
8条答案
按热度按时间zlhcx6iw1#
与大多数现有的答案相反,请注意,实际上有4种方法与查找map中的元素有关(忽略
lower_bound
,upper_bound
和equal_range
,它们不太精确):operator[]
只存在于非const版本中,如前所述,如果不存在,它将创建元素at()
,在C++11中引入,如果元素存在,则返回对元素的引用,否则抛出异常find()
返回元素的迭代器;如果元素不存在,则返回map::end()
的迭代器count()
返回此类元素的数量,在map
中,这是0或1contains()
(从C++20开始)返回元素是否存在。现在语义已经清楚了,让我们回顾一下何时使用哪个:
map
中,那么使用contains()
(从C++20开始)或count()
。map
中,那么使用at()
。map
中,那么使用find()
;不要忘记检查结果迭代器不等于end()
的结果。operator[]
;如果不希望调用类型默认构造函数来创建它,则可以适当地使用insert
或emplace
qybjjes12#
std::map::at()
在找不到元素时抛出out_of_range
异常。这个异常是一种logic_error
异常,对我来说,从使用的Angular 来看,它是assert()
的同义词:它应该用来报告程序内部逻辑中的错误,比如违反逻辑前提或类不变量。此外,您可以使用
at()
访问constMap。所以,对于你的问题:
1.当访问constMap和元素缺失是逻辑错误时,我建议使用
at()
而不是[]
。1.是的,当你不确定元素是否在这里时,最好使用
map::find()
:在这种情况下,它不是逻辑错误,因此抛出和捕获std::logic_error
异常不是非常优雅编程方式,即使我们不考虑性能。kse8i1jr3#
如您所述,有三种不同的方式可以访问map中的元素:
at()
、operator[]
和find()
(也有upper_bound
、lower_bound
和equal_range
,但这些是针对更复杂的情况,你可能想找到下一个/上一个元素等)那么,什么时候应该使用哪一个呢?
operator[]
基本上是“如果它不存在,则创建一个具有默认构造的Map元素”。这意味着它不会抛出(除了在内存分配抛出或键或值构造函数抛出的极端情况下),并且您肯定会获得对所查找元素的引用-现有元素或新创建的元素。at()
如果该键没有元素则抛出。因为你不应该在正常的程序流中使用异常,所以使用at()
就像是在说“我确定有这样的元素”,但是如果你错了,你会得到一个异常(而不是未定义的行为)。如果你不确定元素是否存在,不要使用这个。find()
表示“可能有也可能没有这样的元素,让我们看看......”,并为您提供了对两种情况做出不同React的可能性。因此,这是一种更普遍的方法。qgelzfjb4#
find
、operator[]
和at
都是有用的。find
是很好的,如果你不想意外插入元素,而只是在它们存在的情况下采取行动。at
很好,如果你期望某个东西应该在Map上,如果它不是,你会抛出一个异常。它还可以以比find
更简洁的方式访问const
Map(不能使用op[]
)op[]
是很好的,如果你想插入一个默认的元素,例如单词计数程序,它把一个int0
的每一个第一次遇到的单词(与习惯用法words[word]++;
)。czfnxgou5#
这取决于此功能的需求以及您如何构建项目。如果你应该返回一个对象,但你不能,因为它没有找到,那么它留给你两个选择,如何处理。你可以通过一个异常,或者你可以返回某种sentinel,这意味着什么都没有找到。如果你想抛出一个异常,那么就使用
at()
,因为这个异常会被抛出。如果你不想抛出异常,那么使用find()
,这样你就不必为了返回一个sentinel对象而处理异常。ccgok5k56#
我认为,这取决于你的使用情况。
std::map::at()
的返回类型是对找到的元素的值的左值引用,而std::map::find()
返回迭代器。你可能更喜欢在表达上,
每当在表达式中使用
std::map::at()
的结果时,您都希望该元素存在,并将缺少的元素视为错误。所以异常是处理这个问题的好选择。oxcyiej77#
我想区别在于语义。
std::map::at()
在我的机器上看起来像这样:如您所见,它使用
lower_bound
,然后检查end()
,比较键,并在需要时抛出异常。find()
看起来像这样:其中
_M_t
是存储实际数据的红黑树。显然,这两个函数具有相同的(对数)复杂度。当您使用find()
+ check forend()
时,您所做的事情与at
几乎相同。我会说语义上的区别是:at()
,你假设它在那里。在这种情况下,元素从所需位置丢失的情况是异常的,因此at()
抛出异常。find()
。在这种情况下,元素不存在的情况是正常的。还要注意,find()
返回一个迭代器,您可以将其用于除简单获取其值之外的其他目的。l7wslrjt8#
map::at()返回一个左值引用,当你通过引用返回时,你可以使用它的所有优点,比如方法链。
举例说明:
operator[]
也通过引用返回Map的值,但是如果没有找到键,它可能会插入一个值,在这种情况下容器大小增加1。这需要你格外小心,因为你必须照顾iterator invalidation。
当有可能没有带有这样一个键的元素时,我是否正确地使用map::find()更好?而map::find()是不是更快更优雅的方法呢?
是的,从语义上讲,当你不确定元素的存在时,使用find()是有意义的。即使对于新手来说,这也使代码更容易理解。
至于时间效率,map通常被实现为RB树/某种平衡二叉搜索树,因此find()的复杂度为O(logN)。
C++规格:
int []; int [];
效果:如果map中没有与x等价的键,则将value_type(x,T())插入到map中。要求:key_type必须是CopyInsertable,mapped_type必须是DefaultInsertable into *this。返回:对 *this中x对应的mapped_type的引用。4复杂性:是对数。
T& at(const key_type& x);
const T& at(const key_type& x)const;返回:对 *this中x对应的mapped_type的引用。Throws:一个类型为out_of_range的异常对象,如果不存在这样的元素.复杂性:是对数。