I have an exception class as follows:
#include <exception>
struct InvalidPathException : public std::exception
{
explicit InvalidPathException() {}
const char* what() const;
};
const char*
InvalidPathException::what() const {
return "Path is not valid";
}
When compiling under GCC 4.4 with -Wall -std=c++0x
error: looser throw specifier for 'virtual const char* InvalidPathException::what() const'
error: overriding 'virtual const char* std::exception::what() const throw ()'
Quite right, too, since I'm overriding std::exception
's what()
method that does indeed have a throw()
exception specifier. But as one will often be informed, we shouldn't use exception specifiers. And as I understand it, they are deprecated in C++11, but evidently not yet in GCC with -std=c++0x.
So I'd be interested in the best approach for now. In the code I'm developing I do care about performance and so worry about the oft-mentioned overhead of throw()
, but in reality is this overhead so severe? Am I right in thinking that I'd only suffer it when what()
is actually called, which would only be after such an exception is thrown (and likewise for the other methods inherited from std::exception that all have throw()
specifiers)?
Alternatively, is there a way to work around this error given by GCC?
Empty throw
specifications are useful, as they actually enable compiler optimizations at the caller's site, as Wikipedia knows (I don't have a technical quote handy).
And for reasons of optimization opportunities, nothrow-specifications are not deprecated in the upcoming standard, they just don't look like throw ()
any more but are called noexcept
. Well, yes, and they work slightly differently.
Here's a discussion of noexcept
that also details why traditional nothrow-specifications prohobit optimizations at the callee's site.
Generally, you pay for every throw
specification you have, at least with a fully compliant compiler, which GCC has, in this respect, appearantly not always been. Those throw
specifications have to be checked at run-time, even empty ones. That is because if an exception is raised that does not conform to the throw
specification, stack unwinding has to take place within that stack frame (so you need code for that in addition to the conformance check) and then std::unexpected
has to be called. On the other hand, you potentially save time/space for every empty throw
specification as the compiler may make more assumptions when calling that function. I chicken out by saying only a profiler can give you the definitive answer of whether your particular code suffers from or improves by (empty!) throws
specification.
As a workaround to your actual problem, may the following work?
#define NOTHROW throw ()
and use it for your exception's what
and other stuff.noexcept
, redefine NOTHROW
.As @James McNellis notes, throw ()
will be forward-compatible. In that case, I suggest just using throw ()
where you have to and, apart from that, if in doubt, profile.
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