C++中通过
aMap[key]
和aMap.at(key)
获取值有什么区别?
如果您使用索引运算符
[]
访问当前不属于地图一部分的键,那么它会自动为您添加一个键。这是一个巨大的警告,请考虑到这一点。因此,我更喜欢使用索引运算符 []
进行设置,使用 .find()
/ .at()
进行查找。
使用
.at()
相对于 []
的另一个优点是它可以在 const std::map
上运行,而 []
则不能。
在 C++11 中
map::at
存在(谁知道?)。
如果键不存在,它会抛出异常;如果元素不存在,
find
返回aMap.end()
;如果相应键不存在值,operator[]
值初始化会为相应键返回一个新值。
我喜欢这里的答案,但我认为了解为什么 [] 不能在
const
的 std::map
实例上使用很重要。如果我们看一下这些方法的标准声明:
mapped_type& at(const key_type& k);
const mapped_type& at(const key_type& k) const;
mapped_type& operator[](const key_type& k);
mapped_type& operator[](key_type&& k);
正如我们所见,所有
operator[]
都不是 const
,因此返回的 mapped_type
是可以修改的。另一方面,存在一个 const& at() const
版本,它不允许修改mapped_type,也不允许修改类本身。
现在让我们看看为什么在
operator[]
的实现中会出现这样的情况:
template <class _Key, class _Tp, class _Compare, class _Allocator>
_Tp&
map<_Key, _Tp, _Compare, _Allocator>::operator[](const key_type& __k)
{
return __tree_.__emplace_unique_key_args(__k,
_VSTD::piecewise_construct,
_VSTD::forward_as_tuple(__k),
_VSTD::forward_as_tuple()).first->__get_value().second;
}
在这里我们可以看到,该方法尝试将密钥作为新的唯一密钥对直接放入二叉树中,然后 emplace 方法返回对
std::pair
的引用(无论它是否已经存在)。这棵树是 std::map
的成员,因此返回对其数据的引用可能会修改数据,并且与树本身一起修改数据,从而修改 std::map
类,这就是为什么不可能在 const
上调用此方法
std::map
的实例。
现在我们来看看
at() const
的实现:
template <class _Key, class _Tp, class _Compare, class _Allocator>
const _Tp&
map<_Key, _Tp, _Compare, _Allocator>::at(const key_type& __k) const
{
__parent_pointer __parent;
__node_base_pointer __child = __tree_.__find_equal(__parent, __k);
if (__child == nullptr)
__throw_out_of_range("map::at: key not found");
return static_cast<__node_pointer>(__child)->__value_.__get_value().second;
}
此方法以完全不同的方式访问树。因为它只搜索已经存在于树中的相等项。并使用指向找到的节点的常量指针进行操作。
const
方法的非at()
版本的操作非常相似,但它请求__node_base_pointer
作为参考,从而可以修改它,但仍然消除了用at()
放置新节点的可能性
方法。