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(), e.g., 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, e.g., 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, i.e., 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 ints 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.
Related
The pop() method of std::priority_queue is not declared noexcept, so in theory could throw an exception. But when might it throw an exception, and what might those exceptions be?
It could be marked nothrow, but isn't.
Why std::priority_queue::pop could* not throw
void pop();
Removes the top element from the priority queue. Effectively calls
std::pop_heap(c.begin(), c.end(), comp); c.pop_back();
c is by default an std::vector.
[vector.modifiers]/4&5
void pop_back();
4/ Complexity: The destructor of T is called the number of times equal to the number of the elements erased, but the assignment operator of T is called the number of times equal to the number of elements in the vector after the erased elements.
5/ Throws: Nothing unless an exception is thrown by the assignment operator or move assignment operator of T.
*So only the destructor of T is called and that one cannot throw because of
[requirements.on.functions]/2.4
2/ In particular, the effects are undefined in the following cases:
[...]
2.4/ if any replacement function or handler function or destructor operation exits via an exception, unless specifically allowed in the applicable Required behavior: paragraph.
Why is std::priority_queue::pop not nothrow?
Since an exception thrown from T::~T would lead to UB, the implementation can assume it cannot happen and still conform to the Standard. Another way to deal with it is to let such library functions nothrow(false) and not dealing with it.
Is there complete list (maybe recursively defined) of "code statements" that can lead to exception in c++? Something like this:
1) throw statement (naturally)
2) calls to new
3) calls to any functions from standard library that are documented to be able to throw.
4) calls to any user-defined functions (including constructors) that contain operations from 1-3.
5) Something else? Allocating local objects on stack, operations on built-in types, dereferencing pointers, type casts - are they able to throw?
6) Everything else is exception-free.
By exception-free I don't mean operations that are always successful. Dereferencing a pointer surely isn't. But still it does not make sense to wrap it in try-catch block, think about exception-safety of function dereferencing a pointer, etc. So the code that either successful or leads to undefined behaviour can be considered as exception-free.
Upd. Despite my last paragraph I still got a comment that undefined behaviour also can throw, so let me explain what I mean. Consider following code:
void bar();
Class C{
...
public:
foo() {
something_that_breaks_class_invariants;
bar();
something_that_restores_class_invariants;
}
}
If I correctly understand what exception safety is about, then if bar() can throw exception, this code is bad. I should change the order of statements, or I should wrap bar() in try-catch block, restore class invariants and propagate exception further.
But if bar() either successfully returns or leads to undefined behaviour (because, I don't know, something else is broken), then foo() is ok. foo() can't do anything and shouldn't care about possible undefined behaviour of bar(). In this sense bar() is exception-free, can be marked noexcept, etc.
So my question is: what kinds of statements can be in bar() to consider it exception-free is this sense?
Yes, the list of things that can throw in C++ can be exhaustively defined.
throw expression
new can throw bad_alloc
dynamic_cast can throw bad_cast
typeid can throw bad_typeid
any call to a function that is not noexcept or throw()
The last point also applies to all the implicit function calls of C++: default/copy/move constructors, overloaded operators, destructors (note that those default to noexcept) and conversion operators.
If you are ever in doubt about a particular expression, you can use the noexcept operator to have the compiler tell you whether it's theoretically possible for the expression to throw.
Your list is almost complete. There's indeed one cast that can throw: dynamic_cast<Derived&>. That's because there are no null references. dynamic_cast<Derived*> returns a null pointer instead of throwing.
In all cases, exceptions are thrown when evaluating expressions. Variable definitions may only throw when they contain an expression, e.g. in an initializer or inside a constructor.
The "Undefined Behavior" bit is a red herring. You simply can't reason about a C++ program that has Undefined Behavior, not even about what might have happened prior to that UB. That means we're assuming no UB whenever we are reasoning about defined C++ behavior.
The answer is simple: Any statement that uses an overloadable operator or function that cannot be proven not to throw, can throw. Here are some examples:
template <class T> T foo(const T& arg) { return arg; } //can throw (copy constructor!)
template <class T> void foo(T a, T b) { a+b; } //can throw (+ is overloadable)
template <class T>
void foo(T iter, T end) {
for(; iter < end; iter++) { //both the < and the ++ operator can throw
iter->bar(); //even the -> operator is overloadable and can throw
}
}
In short, whenever you do not have knowledge of the involved types, as is generally the case with templates, you pretty much have to call any statement a throwing statement.
Afaik, the only valid defense against this not to allow exceptions in the first place.
I have an operator[] for my class and all it does is call std::unique_ptr::operator[] on a unique_ptr member. The relevant part is just this:
template <typename T> struct Foo {
T& operator [](const size_t pos) const noexcept
{
return data_[pos];
}
std::unique_ptr<T[]> data_;
};
I've marked the operator as noexcept. However, unique_ptr::operator[] is not noexcept. I am unable to find out why that is, and whether I can just assume that it will never throw. unique_ptr::operator[] itself does not list any exceptions in the documentation (cppreference and MSDN claim it does not define any list of exceptions it might throw.)
So I assume the missing noexcept might either be: a) a mistake, or b) the underlying datatype accessed by the operator might throw. Option a would be nice, since that would mean I can mark my own operator noexcept. Option b would be difficult to understand, since all the operator does it get a reference and it doesn't call anything.
So, long story short, is there any possibility of unique_ptr::operator[] ever throwing, and is it safe to call it from a noexcept function?
So, long story short, is there any possibility of unique_ptr::operator[] ever throwing
Yes. It will simply use [] on the pointer type that it has. And that could throw. Recall that, thanks to deleter gymnastics, the pointer type need not be an actual pointer. It could be a user-defined object type with its own operator[] overload that could throw on out-of-bounds use.
I thought I give it a try (I am not sure of the answer).
I went through the noexcept reference and my understanding is that noexcept is simply indicating that the function should not throw exception, so that the compiler could make more agressive optimisations.
As to why the unique_ptr::operator[] is not noexcept I guess that the one standardising imagined that some implementors may throw and some other may not.
My opinion is that unique_ptr::operator[] may be throwing depending on the implementation of unique_ptr (typically when the index is out of bound).
However depending of the context of your code you could make sure this won't happen and decide to specify noexcept for your operator[].
I have the following unordered_set:
class ArtifactImpl{...};
class ArtifactSetKeyOps
{
public:
std::size_t operator()(const ArtifactImpl& artifact) const noexcept;
bool operator()(const ArtifactImpl& lhs, const ArtifactImpl& rhs) const noexcept;
};
std::unordered_set<ArtifactImpl,
ArtifactSetKeyOps,ArtifactSetKeyOps> artifactSet_;
Note that my hash and predicate template argument/s have a noexcept specification.
Would it be possible for unordered_set::find to throw?
I'm aware that find isn't marked noexcept, but in practice find should not perform allocations...
Would it be acceptable to call find from a noexcept marked function?
e.g:
const ArtifactImpl& foo() noexcept
{
auto pos = artifactSet_.find(key);
//etc...
}
Even though foo() here above goes against find's noexcept specifications, I'm wanting to know whether the specification holds practically iff one provides one's own noexcept hash and comparison.
tl;dr: noexcept seems useful only for move constructor/assignment operator.
If you would dare to accept cplusplus.com or even me as sufficient authority: it does not throw any exception, unlessan aspect does - such as the allocator or a comparator throws, nothing throws.
(I should probably go dig out the relevant ISO passages now...)
However, as to my understanding, noexcept isn't particulary useful here:
Andrzej has a detailed explanation on his blog, from which I (mis)quote the relevant parts here:
noexcept doesn't buy much if the implementation throws despite the specification
it doesn't help with implementing a no-throw exception safety guarantee
and it is unlikely to enable significant optimizations except in one case, related to move semantics:
for certain functions, like vector<T>::push_back using move constructors/assignments of T instead of copy constructors/assignments can dramatically increase performance. However, if this move constructor/assignment can potentially throw, push_back would loose the strong exception safety guarantee. In order to take an advantage of the move operations (where possible) and at the same time keep the strong guarantee, there needs to be a way to determine if a given move operation is potentially throwing or not, and use it or alternatively fall back to good old copying. This is exactly what function std::move_if_noexcept does, but it needs T’s operations to be marked as noexcept where appropriate.
It could throw if you hash function (which it must call) throws. For that reason alone I wouldn't use it. But more importantly, I wouldn't use the noexcept specifier because it goes against the find function's specifications.
Given this statement (which, as a sidenote, is not my preferred coding style)
if( doSomething() ) {}
Does 'the C++ Standard' guarantee that the function is called?
(It's return value has no effect on the execution path, so the compiler
may follow the ideas of shortcut evaluation and optimize it away.)
There's no short-circuit operator involved, so the function is guaranteed to be called if it can't be optimized away without removing side-effects. Quoting the C++11 standard:
[...] conforming
implementations are required to emulate (only) the observable behavior of the abstract machine as explained
below.5
5 This provision is sometimes called the “as-if” rule [...] an actual implementation need not evaluate part of an expression
if it can deduce that its value is not used and that no side effects
affecting the observable behavior of the program are produced.
So, something like
int doSomething() { return 1; }
might be optimized away, but
int doSomething() { std::cout << "d\n"; return 1; }
isn't allowed to.
Additionally, since C++11, you can write more sophisticated functions and still make them evaluated at compile time by using constexpr.