简体   繁体   中英

can std::accumulate throw?

The c++ reference for std::accumulate does not mention any exception to be possibly thrown by std::accumulate , still its definition does not contain noexcept . Assuming one uses types and operations which do not throw, is safe to employ std::accumulate in a member function declared as noexcept , or does one incur in UB?

For example:

#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;
}

Is declaring A::sum() as noexcept a source of UB?

There are preconditions on std::accumulate() , eg, that the end of the range is reachable from the begin of the range. So far the standard library hasn't put noexcept on functions with preconditions (at least, not in general; there may be special cases) as a debugging implementation could assert that there is a problem, eg, by throwing an exception: what happens when undefined behavior is triggered is undefined and implementations are free to define any of that if they wish to do so.

Also, any of the functions called by std::accumulate() are allowed to throw, ie, any noexcept declaration would need to be conditional. I think it is unlikely that the algorithms will get corresponding noexcept declarations in general.

As the specification doesn't mention any case where std::accumulate() throws when called within contract, it won't throw if none of the called operations throws.

Yes, in general it can.

First of all the operations that are customizable through the template arguments and that std::accumulate must perform can throw.

But even aside from that the standard does allow an implementation to throw implementation-defined exceptions if a standard library function does not have a non-throwing exception specification and the description of the function doesn't say otherwise, see [res.on.exception.handling]/4 .

That being said, I would be surprised if the use of std::accumulate in your example would throw. There is no dynamic allocation required, so a potential throwing of std::bad_alloc should not be necessary and that is the most likely candidate for implementation-defined exceptions. The summation, copy and/or move operations on int s are also non-throwing.

In any case adding noexcept to a function does not cause undefined behavior if an exception is thrown inside of it. Instead it is well-defined that, should an exception reach the noexcept function's outer scope, std::terminate will be called, which by default abort the program, but can be customized to some degree.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM