Is there any way in C++ to get a compile-time error or warning if an exception is unhandled? For example, consider this Java code snippet:
public void f()
{
g(); // <-- Java compiler reports "Unhandled exception" error here.
}
public void g() throws Exception
{
}
Can g++ or MSVC do something similar? Or is there any external code parsing tool which can do this? I suppose one could programmatically extend the C++ parser of Eclipse CDT to achieve this, but... are there easier solutions?
Simply, no. C++ exception specifications have a different meaning to Java's exception specifications and they are now deprecated so you should consider avoiding them if possible.
In C++, the checks requested by exception specification are enforced only at runtime. In C++, if a function violates its exception specification the the "unexpected" handler is called. It is not a compile time error to call a function that can potentially throw an arbitrary exception from a function with an exception specification.
ISO/IEC 14882:2011 15.4 [except.spec] / 11:
An implementation shall not reject an expression merely because when executed it throws or might throw an exception that the containing function does not allow.
Short answer: no. There are no checked exceptions in C++. You can try to use an external tool, but TBH I've never seen anyone do that. Just document the interfaces properly.
Related
I'm reading this book on C++ and there's a code example that should behave differently: it should throw an exception or error (sorry for the poor terminology here) anyway it just shouldn't work or so the book says. (the book is rather new so I think its up to date). But in my case the code executes itself and I get the "Exception caught" message.
The author uses a different compiler (WxDev). (I'm using Visual Studio 2019)
#include<exception>
void generate_char_exception() throw(int)
{
throw 'x';
}
int main()
{
try
{
generate_char_exception();
}
catch (...)
{
cout << "Exception caught" << endl;
}
return 0;
}
Picture of the code from the book:
For starters, throw() specifications are deprecated, prefer noexcept. I question how updated your book is, regardless, I suggest you take a look at this list of good C++ books: The Definitive C++ Book Guide and List. For a more in-depth look on throw specification and why it is bad, see http://www.gotw.ca/publications/mill22.htm (thanks user4581301)
Now, to the answer:
According to https://en.cppreference.com/w/cpp/language/except_spec
If the function throws an exception of the type not listed in its
exception specification, the function std::unexpected is called. The
default function calls std::terminate, [...]
So the book seems to be right, and when using g++ you get the expected behavior: https://onlinegdb.com/Sy_7DzUmB
terminate called after throwing an instance of 'char'
Aborted
If you use throw(char) the exception gets caught.
Microsoft Visual Studio 2019 does not implement that kind of exception specification: https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-3-c4290?view=vs-2019
A function is declared using exception specification, which Visual C++
accepts but does not implement. Code with exception specifications
that are ignored during compilation may need to be recompiled and
linked to be reused in future versions supporting exception
specifications.
And from: https://learn.microsoft.com/en-us/cpp/cpp/exception-specifications-throw-cpp?view=vs-2019
throw(type): (C++14 and earlier) The function can throw an exception
of type type. The compiler accepts the syntax, but interprets it as
noexcept(false) [...]
Interestingly enough this is also what Herb Sutter states in the linked article
At least one popular C++ compiler (Microsoft’s, up to version 7.x)
parses exception specifications but does not actually enforce them,
reducing the exception specifications to glorified comments
Finally, this answer is more a curiosity, throw() has been deprecated (and also removed) in its various forms from the more recent versions of the language: https://en.cppreference.com/w/cpp/language/except_spec .
Prefer noexcept: https://en.cppreference.com/w/cpp/language/noexcept_spec
Introduction:
In Java, if you do not catch an exception, your code doesn't even compile, and the compiler crashes on unhandled exception.
Question:
Is there a way to tell GCC to be "strict" as Java in this case, and to raise an error or at least a warning on unhandled exception?
If not - are there IDEs (for Unix, please) that can highlight such cases as a warning?
It is not possible in C++. Exception specification is a part of a function declaration but not a part of its type. Any indirect call (via pointer or virtual call) just completely wipes any information about exceptions.
Exception specifications are deprecated anyway in C++11 in favour of noexcept, so it is unlikely any compiler would bother to enhance this language feature.
The only guarantee you can put on a C++ function is that it never throws an exception at all:
void f() noexcept;
However, this will terminate the program at runtime when an exception is thrown. It's not verified at compile-time.
If you want to guarantee that an error is handled, the closest you can get is returning a value of a type that wraps boost::variant<OK, Error> with a member function that takes two callbacks: a callback for the OK case and one for the Error case.
You can ALWAYS use:
int main()
{
try {
... your usual main ...
}
catch(...)
{
std::cerr << "Unhandled exception caught" << std::endl;
}
}
However, that is a fairly poor solution.
Unfortunately, the nature of C++ makes it very hard to catch the situation where something throws an exception and it's not handled, since just about everything has the potential to throw exceptions. I can only think of code-review - perhaps code analyzing tools, such as that built around CLANG will have the capability of doing this, but it probably won't be 100% accurate. In fact, I'm not even sure that the Clang Analyzer fully understands throw/try/catch currently, as it seems to not catch some fairly fundamental errors http://clang-analyzer.llvm.org/potential_checkers.html (see the "exceptions" heading).
First, your statement concerning Java is false; only certain
types of exceptions prevent the code from compiling. And for
the most part, those types of exceptions correspond to things
that are better handled by return codes. Exceptions are normally
only an appropriate solution when propagating an error through
a large number of functions, and you don't want to have to add
exception specifications for all of those functions.
That's really why Java makes its distinctions: exceptions that
derive from java.lang.Error should usually be crashes
(assertion failures and the like in C++); and exceptions that
derive from java.lang.RuntimeException should be exceptions in
C++. Neither are checked in Java, either, because it isn't
reasonable to have every function declare that it might throw
one of them.
As for the rest, the exceptions which you want to catch
immediately in the calling code, they are generally best handled
by return codes, rather than exceptions; Java may use exceptions
here because it has no out arguments, which can make using
return codes more awkward. Of course, in C++, you can also
silently ignore return codes, which is a drawback (but
historical reasons, etc.). But the real issue is the contract,
which is far more complex than function f might throw/return x;
it's more along the lines of "function f will throw/return x,
if condition c is met". And I know of no language which has
a means of enforcing that. In C++ (and for checked exceptions
in Java), exception specifications are more along the lines of
"function f will not throw anything but x". Which is generally
not very useful, unless "x" means all exceptions. In order to
write really robust code, you need a few functions which are
guaranteed never to throw. Interestingly enough, you can
specify this in C++, both pre-C++11 (throw()) and post
(noexcept); you cannot in Java, because you can't specify that
a function won't throw a java.lang.RuntimeError.
(Or a java.lang.Error, but that's less of an issue, since if
you get one of those, you're application is hosed anyway. Just
how are you expected to recover from
java.lang.VirtualMachineError? And of course, you can't
really expect to be able to recover from a segment violation in
C++ either. Although... java.lang.OutOfMemoryError derives
from java.lang.VirtualMachineError; although not easy, and not
always applicable, I've written C++ code which successfully
recovered from std::bad_alloc.)
Short version: What is "an exception as described in the C++ standard, 17.6.4.10 [res.on.exception.handling]" and how do I catch one?
Long version...
I would like to catch the exceptions thrown from the version of boost::create_directories() that does not take a system::error_code as an argument. The Boost Filesystem Error Reporting Documentation says that create_directories() reports errors either by...
a> throwing a boost::filesystem_error when a call by the implementation to an operating system or other underlying API results in an error that prevents the function from meeting its specifications, or...
b> throwing an exception as described in the C++ standard, 17.6.4.10 [res.on.exception.handling] when there is a failure to allocate storage.
The first case is obvious and I have handled that situation. But I can't find any explanation of how to handle the second case. Googling "exception as described in the C++ standard, 17.6.4.10 res.on.exception.handling" yields three articles (that could be a record for a non-zero search result), and none of them tell me how to handle such an exception.
Can anyone help?
I think what they mean is that they will (indirectly) throw std::bad_alloc. You may not actually want to try to catch that though, as a program which has run out of memory may not be able to continue in any case. Up to you though--I read this same documentation just the other day and that's the conclusion I came to.
The actual paragraph of the current C++11 standard regarding exception handling is §17.6.5.12.
But there is no helpful information on what a boos library may throw except if the have throw specifying paragraphs.
I think what you want is to catch a std::exception since the most likely case in terms of " throwing an exception [...] when there is a failure to allocate storage" is a std::bad_alloc which derives from std::exception.
Just came to the same question while reading boost::filesystem documentation. In n4296 draft of C++14 standard following declared:
17.6.5.12 Restrictions on exception handling
Any of the functions defined in the C++ standard library can report a failure by throwing an exception of a type described in its Throws: paragraph. An implementation may strengthen the exception specification for a non-virtual function by adding a non-throwing noexcept-specification.
A function may throw an object of a type not listed in its Throws clause if its type is derived from a type named in the Throws clause and would be caught by an exception handler for the base type.
This doesn't sound informative, thus the real answer needs to be found in boost sources, which are currently hosted on Github. Actually, per implementation defined there the boost::filesystem::filesystem_error exception will be thrown if ec argument was not provided.
if (ec == 0)
BOOST_FILESYSTEM_THROW(filesystem_error(
"boost::filesystem::create_directories", parent, local_ec));
I was wondering if there is some compiler parameter, preferably in gcc (g++) which treats the lack of try/catch blocks as errors. This is the standard behavior in java and I was alway fond of it.
Since checked exceptions in Java rely on the throw signature, you can read why you will not want to use throw function signatures in C++ in this question on SO.
Well, using exception specifications is generally a bad idea: http://cplusplus.co.il/2009/10/06/exception-specifications/
And if not using these, the compiler basically has no way of knowing which exception may be thrown, so there's no way to do that.
What you could do, is provide your own implementation of std::terminate (by invoking std::set_terminate()) and handle uncaught exceptions there.
One thing you can do in C++ with exceptions is use exception specifications on your functions. That doesn't actively prevent non-listed exceptions from being thrown from that function, but it makes them errors (and maps them all to the predefined unexpected().
So int f() throw (); is C++ for "treat any exception being raised from function f as an error".
C++ provides a syntax for checked exceptions, for example:
void G() throw(Exception);
void f() throw();
However, the Visual C++ compiler doesn't check them; the throw flag is simply ignored. In my opinion, this renders the exception feature unusable. So my question is: is there a way to make the compiler check whether exceptions are correctly caught/rethrown? For example a Visual C++ plugin or a different C++ compiler.
PS. I want the compiler to check whether exceptions are correctly caught, otherwise you end up in a situation where you have to put a catch around every single function call you make, even if they explicitly state they won't throw anything.
Update: the Visual C++ compiler does show a warning when throwing in a function marked with throw(). This is great, but regrettably, the warning doesn't show up when you call a subroutine that might throw. For example:
void f() throw(int) { throw int(13); }
void h() throw() { g(); } //no warning here!
What's funny is that Java has checked exceptions, and Java programmers hate those too.
Exception specifications in C++ are useless for 3 reasons:
1. C++ exception specifications inhibit optimization.
With the exception possibly of throw(), compilers insert extra code to check that when you throw an exception, it matches the exception specification of functions during a stack unwind. Way to make your program slower.
2. C++ exception specifications are not compiler-enforced
As far as your compiler is concerned, the following is syntactically correct:
void AStupidFunction() throw()
{
throw 42;
}
What's worse, nothing useful happens if you violate an exception specification. Your program just terminates!
3. C++ exception specifications are part of a function's signature.
If you have a base class with a virtual function and try to override it, the exception specifications must match exactly. So, you'd better plan ahead, and it's still a pain.
struct A
{
virtual int value() const throw() {return 10;}
}
struct B : public A
{
virtual int value() const {return functionThatCanThrow();} // ERROR!
}
Exception specifications give you these problems, and the gain for using them is minimal. In contrast, if you avoid exception specifications altogether, coding is easier and you avoid this stuff.
Exception specifications are pretty useless in C++.
It's not enforced that no other exceptions will be thrown, but merely that the global function unexpected() will be called (which can be set)
Using exception specifications mainly boils down to deluding yourself (or your peers) into some false sense of security. Better to simply not bother.
Have a look at this:
http://www.gotw.ca/publications/mill22.htm
basically exception specifications are unworkable/unusable but that doesn't make exceptions unworkable.
As for your question, there is no way to get the compiler to check that every type thrown is caught somewhere higher in the code, I expect compilation units make this difficult and it's impossible to do it for code intended to be used in a library (where the top level is not available at compile time). If you want to be sure everything is caught then stick a catch(...) at the very top of you code.
Because the standard says so. The exception declaration doesn't mean that no other exception will be thrown. It means that if an undeclared exception is thrown, there will be called a special global function called unexpected(), which by default terminates the program. Generally declaring exceptions in functions is discouraged (maybe except for empty exception list) as the standard behaviour is not very helpful.
To detect prior to runtime cases such as ...
extern void f() throw (class Mystery);
void g() throw() {
f() ;
}
... you need static analysis. Yes, the compiler is doing plenty of static analysis, but because the standard is "raise std::unexpected if the throw doesn't match," and it is perfectly legal to write a routine that throws an object that does not match the specifier, the compiler implementers neither warn nor remark.
Static analysis tools that claim to provide warning service include Gimpel Software's lint for C++ ...
1560 Uncaught exception 'Name' not on throw-list for function 'Symbol'
and, according to this answer to a prior question, QA C++.
I cannot check this for lack of a MSVC installation, but are you really sure the compiler ignores the throw() specification?
This MSDN page suggests that Microsoft is aware of throw() and expects their compiler to handle it correctly. Well, almost, see the note about how they depart from the ANSI/ISO standard in some details.
Edit: In practice, though, I agree with Patrick: Exception specifications are mostly useless.