【问题标题】:Why is there no `noexcept` specifier on std::unordered_map::count?为什么 std::unordered_map::count 上没有 `noexcept` 说明符?
【发布时间】:2016-05-28 09:56:29
【问题描述】:

我正在阅读C++ reference page 关于std::unordered_map。这 emptysize 方法是 noexcept 合格的,但不是 count

我认为它不应该抛出count

我错过了什么吗?

【问题讨论】:

  • 我认为没有什么能阻止散列函数或相等谓词抛出。
  • 好的。我也想知道为什么clearnoexcept 指定的。存储的实例可能会抛出它们的析构函数。为什么会有不同的行为?
  • @RichardDally:析构函数不能抛出异常
  • @MooingDuck 析构函数可以抛出,尽管故意这样做被认为是不好的风格
  • @M.M:我查过了,你是对的。默认情况下它们不能抛出,但如果你明确将它们标记为noexcept(false),那么它们可以抛出。

标签: c++ c++11 language-lawyer unordered-map noexcept


【解决方案1】:

因为需求是这样说的:

count 返回匹配特定键的元素的数量,并且键比较是根据任何无序关联容器类型XX::key_type 类型的对象评估的(实例化的std::unordered_maps 就是这样的容器)

n3337 23.2.5/5 [unord.req]

如果容器的键相等谓词在传递这些值时返回 true,则认为 Key 类型的两个值 k1k2 是等效的。 ...对于同一容器中的任意两个键k1k2,调用pred(k1, k2) 应始终返回相同的值。 ...

对于无序映射,X::key_type 被定义为其模板参数列表的一部分:

template<
    class Key,
    //    ^^^ member type key_type set from this parameter
    class T,
    class Hash = std::hash<Key>,
    class KeyEqual = std::equal_to<Key>,
    //    ^^^^^^^^ member type key_equal set from this parameter
    class Allocator = std::allocator< std::pair<const Key, T> >
> class unordered_map;

我可以在key_type 上找到的唯一限制也适用于value_type

n3337 23.2.5/9 [unord.req]2

...表 96 中对 value_type 的要求适用于 key_typemapped_type

所以我们只需要知道表 96 中对value_type 的要求,它指定了Container 的要求。在第一行,我们有:

n3337,表 963

X::value_type |返回T | 要求: TDestructible

其中X 又是容器的类型,T 是它存储的对象的类型。 Destructibleobjects 不允许有抛出的析构函数。这是他们唯一的要求。

n3337,表 24

u.∼T()u拥有的所有资源都被回收,不传播异常

uT 类型的对象,满足 Destructible 的要求)

因此,对于unordered_map键比较函数提供的抛出保证没有限制,因此std::equal_to提供的operator==操作不保证实现要求的行为。 key 本身没有这样的限制,所以:允许比较函数抛出,任何使用比较函数的函数也允许抛出。 count 需要用 key 计算存储的值将提供的键与比较函数匹配,因此它可能会抛出。


clear 可能是noexcept,因为标准禁止抛出析构函数:

17.6.4.8/1,24 [res.on.functions]

在某些情况下(替换函数、处理函数、对用于实例化标准库模板组件的类型的操作),C++ 标准库依赖于 C++ 程序提供的组件。如果这些组件不符合其要求,则标准不会对实施提出任何要求。

特别是在以下情况下效果是不确定的:

...

  • 如果任何替换函数或处理函数或析构函数操作通过异常退出,除非在适用的必需行为:段落中明确允许。

...

由于唯一依赖于客户端的代码clear执行可能不会抛出异常,而实现也不需要,它可能并且已经被标记为noexcept


注意事项:

1. n4140 标准草案(接近 c++14)似乎根本没有改变这个条款。

2。 n4140 保留了这一措辞,从第 9 条移至第 10 条。

3。 Container的要求也列在n4140的表96中,将T的要求列为Erasable,这对operator==也没有限制

4。该条款的措辞在 n4140 中没有改变。

【讨论】:

  • [res.on.functions]/2.4 禁止全面抛出析构函数,并且至少从 C++03 开始​​就这样做了。
  • @T.C.固定的。再次感谢你给我这个条款。
猜你喜欢
  • 2016-04-10
  • 2021-01-02
  • 1970-01-01
  • 2021-12-21
  • 2016-02-13
  • 1970-01-01
  • 2015-06-28
  • 1970-01-01
  • 2017-07-11
相关资源
最近更新 更多