对逻辑使用std::out_of_range是否错误

Is using std::out_of_range for logic bad?

本文关键字:of range 是否 错误 out std      更新时间:2023-10-16

在我的项目中,我有很多这样的情况:

constexpr size_t element_count = 42;
std::array<bool, element_count> elements;
for(size_t i = 0; i < element_count; ++i){
if(i > 0 && elements[i - 1]){/*do something*/}
else{/*do something else*/}
if(i < element_count - 1 && elements[i + 1]){/*do something*/}
else{/*do something else*/}
}

如果不检查是i > 0还是i < element_count,我将得到未定义的行为。如果我使用std::array::at而不是operator[],我可以获得std::out_of_range异常。我想知道仅仅依赖这样的例外是否有任何问题:

for(size_t i = 0; i < element_count; ++i){
try{
if(elements.at(i - 1)){/*do something*/}
}
catch(const std::out_of_range& e){/*do something else*/}
try{
if(elements.at(i + 1)){/*do something*/}
}
catch(const std::out_of_range& e){/*do something else*/}
}

在这个例子中,它是更多的代码,但在我的真实项目中,它会减少代码量,因为我使用了很多多维数组,并对多维进行边界检查。

从某种意义上说,它不会起作用,但仅此而已。使用异常进行基本流控制(这似乎就是你在这里所做的)通常是有原因的,我想我从未在循环中见过这样的情况:

  • 使得阅读和推理代码变得更加困难,这也是因为使用异常进行流控制(而不是用于错误处理,这是C++中的意思)是出乎意料的
  • 更难读通常也意味着更难写,更难发现错误
  • 你实际上已经犯了一个错误,或者至少引入了一个行为改变:i>0&amp;elements[i-1]求值为false不会导致调用"其他东西">
  • 如果减少代码量导致代码可读性降低或更差,那么减少代码量就不再是一个好目标
  • 可能性能较差

现在看看实际的代码会很有趣,但我怀疑它可能不需要任何边界检查,例如,让循环从1而不是0开始。或者,如果这是一个递归模式,您可以为迭代编写一个辅助函数(或使用现有的),在一次迭代中访问多个元素。这将是代码量的减少,这实际上是值得的