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
如果您在标记为or的函数中抛出异常,noexcept(true)
那么您的程序将被终止(标准 15.4.9)
每当抛出异常并且搜索处理程序 (15.3) 遇到具有不允许异常的异常规范的函数的最外层块时,然后,
- 如果异常规范是动态异常规范,则调用函数 std::unexpected() (15.5.2),
- 否则,调用函数 std::terminate() (15.5.1)。
只要这是可以接受的,那么你就可以了。如果您不能容忍程序终止,那么它是不安全的。
这是安全的。如果发生异常,声明函数noexcept
将导致程序立即终止(通过调用)。terminate()
只要不抛出异常,一切都很好。
我们没有完整的场景来准确确定该函数是否能够抛出。
您的假设是正确的:由于您正在做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; }
}
即使
v.at(idx)
理论上可以抛出out_of_range
异常,但实际上不是由于边界检查?
从理论上讲,它不能。
如果您从理论上考虑该函数,那么边界检查是您必须考虑的关于该函数作为一个整体的理论的一部分,因此它可以抛出的唯一理论方法是是否存在一个idx >= v.size()
条件t 是真的,但还是v.at(idx)
扔了。
所以在你说它“理论上可以抛出”是错误的。
(在实践中,如果您at()
在使用中的实现中有错误,它可能会抛出,但是您会遇到更大的问题,并且noexcept
可能导致您这样做可能会更好)。
big-O 组织中的某个人可能做得很聪明,并从中派生了他的类std::vector<int>
,然后重载了 size() 和 at() 以按照自己的喜好扔。然后在代码中的某个地方调用了您的函数,但令所有人惊讶的是,程序终止而不是异常被更高层捕获。
确实牵强附会,但这不仅仅是关于std::vector<int>
... 的问题,而是关于背后的编程实践的问题。
不幸的是,您假设您的输入无法保证,这就是它不安全的原因;至少在大型代码域中。