理论上(但实际上)抛出函数是否应该声明为 noexcept?

Should a theoretically, but not practically, throwing function be declared noexcept?

声明以下函数是否安全 noexcept 即使 v.at(idx) 理论上可以抛出 out_of_range 异常,但实际上不是由于边界检查?

int get_value_or_default(const std::vector<int>& v, size_t idx) noexcept {
    if (idx >= v.size()) {
        return -1;
    }
    return v.at(idx);
}

很安全。如果发生异常,声明函数 noexcept 将导致程序立即终止(通过调用 terminate())。只要不抛出异常就没问题。

你对"safe"的定义是什么?如果您在标记为 noexceptnoexcept(true) 的函数中抛出异常,那么您的程序将被终止(标准 15.4.9)

Whenever an exception is thrown and the search for a handler (15.3) encounters the outermost block of a function with an exception-specification that does not allow the exception, then,

  • if the exception-specification is a dynamic-exception-specification, the function std::unexpected() is called (15.5.2),
  • otherwise, the function std::terminate() is called (15.5.1).

只要能接受就没问题。如果你不能容忍程序终止那么它是不安全的。

我们没有完整的场景来确切地确定该函数是否能够抛出。


您的假设虽然是正确的:因为您正在做 std::vector::at 无论如何都会做的事情,所以在给定的上下文中 不太可能 有害。然而,一般来说,这样的函数 可能 是无效因素的主题,因此可能会抛出异常。这些可能是线程、进程或信号,它们可能会交错执行可能修改 std::vector 的代码,这些代码无法安全处理,std::vector::at.

也不能

如果你也想考虑这些可能性,你需要有类似

的东西
int get_value_or_default(const std::vector<int>& v, size_t idx) noexcept       
{
    try { return v.at(idx); }
    catch (std::out_of_range const& e) { return -1; }
}

even though v.at(idx) could theoretically throw a out_of_range exception, but practically not due to the bounds check?

理论上不能。

如果您从理论上考虑该函数,那么边界检查是您必须考虑的关于该函数整个理论的一部分,因此它可能抛出的唯一理论上的方法是是否存在idx >= v.size() 不成立但 v.at(idx) 抛出的条件。

所以在你的陈述中 "could theoretically throw" 是错误的。

(实际上它可能会抛出,如果你在使用 at() 的实现中有一个错误,但是你会遇到更大的问题并且爆炸,因为 noexcept 可能会导致你这样做可能会更好)。

big-O 组织中的某个人可能做得很聪明,从 std::vector<int> 中导出了他的 class,然后重载了 size() 和 at() 以按照他的喜好进行抛出。然后在代码的某处调用了您的函数,但令所有人惊讶的是程序终止了,而不是异常被更高层捕获。

确实牵强,但这不是一个关于std::vector<int> ...的问题,而是关于背后的编程实践。

不幸的是,您假设有关您的输入的事情无法得到保证,这就是为什么它 不安全;至少在大型代码域中。