It is worth noting that there was an interesting discussion in circles of power about nothrow-related issues. I highly recommend reading these:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3227.html
http://www.stroustrup.com/N3202-noexcept.pdf
Apparently, quite influential people are interested in adding some sort of automatic nothrow deduction to C++.
After some pondering I've changed my position to almost opposite, see below
Consider this:
when you call a function that has noexcept
on declaration -- you benefit from this (no need to deal with unwindability, etc)
when compiler compiles a function that has noexcept
on definion -- (unless compiler can prove that function is indeed nothrow) performance suffers (now compiler needs to ensure that no exception can escape this function). You are asking it to enforce no-exceptions promise
I.e. noexcept
both hurts you and benefits you. Which is not the case if function is inlined! When it is inlined -- there is no benefit from noexcept on declaration whatsoever (declaration and definition become one thing)... That is unless you are actually want compiler to enforce this for safety sake. And by safety I mean you'd rather terminate than produce wrong result.
It should be obvious now -- there is no point declaring inlined functions noexcept
(keep in mind that not every inline function is gonna get inlined).
Lets have a look at different categories of functions which don't throw (you just know they don't):
non-inlined, compiler can prove it doesn't throw -- noexcept
won't hurt function body (compiler will simply ignore specification) and call sites will benefit from this promise
non-inlined, compiler can't prove it doesn't throw -- noexcept
will hurt function body, but benefit call sites (hard to tell what is more beneficial)
inlined, compiler can prove it doesn't throw -- noexcept
serves no purpose
inlined, compiler can't prove it doesn't throw -- noexcept
will hurt call site
As you see, nothrow
is simply badly designed language feature. It only works if you want to enforce no-exception promise. There is no way to use it correctly -- it can give you "safety", but not performance.
noexcept
keyword ended up being used both as promise (on declaration) and enforcement(on definition) -- not a perfect approach, I think (lol, second stab at exception specs and we still didn't get it right).
So, what to do?
declare your behavior (alas, language has nothing to help you here)! E.g.:
void push_back(int k); // throws only if there is no unused memory
don't put noexcept
on inline functions (unless it is unlikely to be inlined, e.g. very large)
for non-inline functions (or function that is unlikely to be inlined) -- make a call. The larger function gets the smaller noexcept
's negative effect becomes (comparatively) -- at some point it probably makes sense specifying it for callers' benefit
use noexcept
on move constructor and move assignment operator (and destructor?). It could affects them negatively, but if you don't -- certain library functions (std::swap, some container operations) won't take the most efficient path (or won't provide the best exception guarantee). Basically any place that uses noexcept
operator on your function (as of now) will force you to use noexcept
specifier.
use noexcept
if you don't trust calls your function makes and rather die than have it behave unexpectedly
pure virtual functions -- more often than not you don't trust people implementing these interfaces. Often it makes sense buying insurance (by specifying noexcept
)
Well, how else noexcept
could be designed?
I'd use two different keywords -- one for declaring a promise and another for enforcing it. E.g. noexcept and force_noexcept. In fact, enforcement isn't really required -- it can be done with try/catch + terminate() (yes, it will unwind the stack, but who cares if it is followed by std::terminate()?)
I'd force compiler to analyze all calls in given function to determine if it can throw. If it does and a noexcept promise was made -- compiler error will be emitted
For code that can throw, but you know it doesn't there should be a way to assure compiler that it is ok. Smth like this:
vector<int> v;
v.reserve(1);
...
nothrow { // memory pre-allocated, this won't throw
v.push_back(10);
}
if promise is broken (i.e. someone changed vector code and now it provides other guarantees) -- undefined behavior.
Disclaimer: this approach could be too impractical, who knows...