I'm trying to write exception safe code. I find that using C++11's noexcept specifier makes this goal a whole lot more achievable.
The general idea, of course, is that a function should be marked as 'noexcept' if, and only if all the functions that it calls are also marked as 'noexcept'.
The problem is that in a large code base, where patches from different people are often merged together, it is hard to ensure that this consistency is maintained.
So I would like to be able to run a static analysis that could list all places where a function that is marked 'nothrow' calls a function that is not marked as 'nothrow'.
As far as I can see in the man-page, GCC cannot help me here. Are there any stand-alone tools that can help me? Or maybe some other compilers?
It certainly seems possible if you avoid pointer to functions (and deem them unsafe) by using the ABT of the program. Clang's AST is (despite its name) such an ABT: you will see both declarations and definitions of the functions. By doing your work one definition at a time, you will already have a good baseline.
On the other hand, I wonder whether this is practical. See, the problem is that any function performing a memory allocation is (voluntarily) marked as potentially throwing (because new
never returns null, but throws bad_alloc
instead). Therefore, your noexcept
will be limited to a handful of functions in most cases.
And of course there are all the dynamic conditions like @GManNickG exposed, for example:
void foo(boost::optional<T> const t&) {
if (not t) { return; }
t->bar();
}
Even if T::bar
is noexcept
, dereferencing an optional<T>
may throw (if there is nothing). Of course, this ignores the fact that we already ruled this out (here).
Without having clear conditions on when a function might throw
, static
analysis might prove... useless. The language idioms are designed with exceptions in mind.
Note: as a digression, the optional class could be rewritten so as not to exposed dereferencing, and thus be noexcept
(if the callbacks are):
template <typename T>
class maybe {
public:
template <typename OnNone, typename OnJust>
void act(OnNone&& n, OnJust&& j) noexcept(noexcept(n()) and
noexcept(j(std::declval<T&>())))
{
if (not _assigned) { n(); return; }
j(*reinterpret_cast<T*>(&_storage));
}
private:
std::aligned_storage<sizeof(T), alignof(T)>::type _storage;
bool _assigned;
};
// No idea if this way of expressing the noexcept dependency is actually correct.
The clang-tidy check bugprone-exception-escape attempts to find functions which may throw an exception directly or indirectly, when they should not. This includes checking functions marked with throw()
or noexcept
.
https://clang.llvm.org/extra/clang-tidy/checks/bugprone/exception-escape.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With