unordered_set::find 和 noexcept

unordered_set::find and noexcept

我有以下 unordered_set:

class ArtifactImpl{...};

class ArtifactSetKeyOps
{
  public:
    std::size_t operator()(const ArtifactImpl& artifact) const noexcept;
    bool operator()(const ArtifactImpl& lhs, const ArtifactImpl& rhs) const noexcept;
};

std::unordered_set<ArtifactImpl,
  ArtifactSetKeyOps,ArtifactSetKeyOps> artifactSet_;

请注意,我的散列和谓词模板 argument/s 有一个 noexcept 规范。

我知道 find 没有标记为 noexcept,但实际上 find 不应该执行分配...

例如:

const ArtifactImpl& foo() noexcept
{
  auto pos = artifactSet_.find(key);
  //etc...
}

尽管上面的 foo() 违背了 find 的 noexcept 规范,但我想知道该规范是否实际上有效,前提是提供了自己的 noexcept 哈希和比较。

如果您的散列函数(它必须调用)抛出,它可能会抛出。仅出于这个原因,我不会使用它。 但更重要的是,我不会使用 noexcept 说明符,因为它违反了 find 函数的规范。

tl;dr: noexcept 似乎只对 move constructor/assignment 运算符有用。

如果你敢于接受 cplusplus.com 甚至我作为足够的权威:它不会抛出任何异常,除非一个方面抛出 - 例如分配器或比较器抛出,什么都不抛出。
(我现在应该去挖掘相关的ISO段落了……)

然而,据我了解,noexcept 在这里不是特别有用:

Andrzej has a detailed explanation on his blog,我在这里(误)引用了相关部分:

  • noexcept 如果实施抛出尽管规范
  • 也没什么用
  • 它无助于实现不抛出异常的安全保证
  • 并且不太可能启用重大优化,除非在一种情况下与移动语义相关:

for certain functions, like vector<T>::push_back using move constructors/assignments of T instead of copy constructors/assignments can dramatically increase performance. However, if this move constructor/assignment can potentially throw, push_back would loose the strong exception safety guarantee. In order to take an advantage of the move operations (where possible) and at the same time keep the strong guarantee, there needs to be a way to determine if a given move operation is potentially throwing or not, and use it or alternatively fall back to good old copying. This is exactly what function std::move_if_noexcept does, but it needs T’s operations to be marked as noexcept where appropriate.