可以std ::积累投掷吗?

时间:2019-12-26 21:26:12

标签: c++ exception noexcept accumulate

std::accumulate的c ++参考未提及std::accumulate可能抛出的任何异常,但其定义中不包含noexcept。假设有人使用不会抛出的类型和操作,可以安全地在声明为std::accumulate的成员函数中使用noexcept,还是有人在UB中发生?

例如:

#include <iostream>
#include <numeric>
#include <vector>

class A {
  std::vector<int> m_v;
public:
  A(std::size_t N) : m_v(N, 1) { }
  int sum() const noexcept { return std::accumulate(m_v.begin(), m_v.end(), 0); }
};

int main()
{
     A x{3};
     std::cout << x.sum() << std::endl;
     return 0;
}

是否将A::sum()声明为noexcept的UB来源?

2 个答案:

答案 0 :(得分:2)

std::accumulate()上有一些先决条件,例如,从范围的起点可以到达范围的终点。到目前为止,标准库还没有将noexcept放在具有前提条件的函数上(至少不是一般情况;可能会有特殊情况),因为调试实现可以​​断言存在问题,例如,抛出异常:触发​​未定义行为时会发生未定义的情况,实现者可以自由定义任何行为。

此外,允许std::accumulate()调用的任何函数都可以抛出,即,任何noexcept声明都必须是有条件的。我认为算法一般不会获得相应的noexcept声明。

由于规范中没有提到在合同内调用std::accumulate()时抛出的情况,因此如果没有被调用的操作都抛出,则不会抛出。

答案 1 :(得分:1)

是的,通常可以。

首先可以通过模板参数自定义并且span { color: red}必须执行的操作会抛出。

但是,除此之外,如果标准库函数没有非抛出异常规范,并且该函数的描述未另外说明,那么该标准确实允许实现抛出实现定义的异常,请参见{{3 }}。

话虽如此,如果您的示例中使用<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <h2>We have cows in our farm cowshed</h2> <h2>C++ Apps $var$ in $var$moretext</h2>,我会感到惊讶。不需要动态分配,因此不需要std::accumulate的潜在抛出,并且这是实现定义的异常的最有可能的候选者。在std::accumulate上的求和,复制和/或移动操作也没有抛出。

在任何情况下,如果向函数中添加std::bad_alloc,如果在其中引发异常,则不会导致未定义的行为。取而代之的是,如果异常到达int函数的外部范围,则将明确定义noexcept,它将被调用,默认情况下将中止程序,但可以在一定程度上进行自定义。

相关问题