I'm working through a book on C++ and in the chapter on errors it has this program (I left a couple of minor things out but it's mostly this):
int main()
try {
// our program (<- this comment is literally from the book)
return 0;
}
catch(exception& e) {
cerr << "error: " << e.what() << '\n';
return 1;
}
catch(...) {
cerr << "Unknown exception\n";
return 2;
}
This compiled but of course it did nothing so I'm still wondering about
- why there isn't a set of curly braces enclosing everything after main()? Are the blocks or shall I call them "catchphrases" (ha!) part of main() or not?
- If they are functions how come there's no "int" before catch(whatever)?
- If they're not functions, what are they?
- re catch(...), I've never seen ellipses used that way. Can I use ellipses anywhere to mean "anything"?
It's
function-try block
. Yes, it's legal, but not needed in more cases. Look at this answer for explanations. What is the meaning of this syntax?1) That's a feature of C++, function try-catch block (see here, for example)
2) And yes,
catch(...) { /* absolutely any exception gets caught here */ }
That is a rarely used feature of the language. You can enclose a whole function in a
try
catch block:The feature is rarely used as it is almost never useful. In the case of a regular function, you can just have a try/catch block that covers all the code of the function, so in this case the feature would not be needed. It has limited functionality in constructors, as it allows catching exceptions on the initializer list, that cannot be enclosed in a try/catch block otherwise.
But the problem there is that there is very little that can be done in the catch block: construction failed so an exception must be thrown (the catch block can throw a different exception to what was caught, but it has to throw). At the same time, you cannot really perform any cleanup, since at the point where the exception is caught you might not know which of the elements in the initialization list threw, which means that you might not know (in the general case) which of the member objects have been constructed or not.
If you use a try block directly instead of braces, the try block catches everything that happens in the function. This is useful in constructors so you can catch exceptions in the initialization list.
This will catch exceptions from bar's constructor:
This will only catch exceptions in the body:
Not sure about the missing curly braces around the main function, but it looks like others answered that all ready.
As for the rest of your question, try catch blocks are not functions outside the main, and do not need an
int
in front of them.try {}
: The program will try to run anything within this block, if it fails for whatever reason, it will be caught by the catch blocks.catch (exception) {}
: When an exception is thrown, it will be caught by a catch block with the specific Exception as its parameter, and allow for the programmer to handle that case.catch (...) {}
: Should catch anything that makes it through the first catch block..There is, it just has the keyword
try
before the opening brace, and somecatch
blocks after the end ofmain
.They're keywords, not functions, and they're part of main, despite the
try
coming between theint main()
definition and its{}
body. See the motivating case below for another example.there are a couple of overloaded meanings of ellipsis in C++.
catch(...)
means catch anything, it's like a wildcard for the exception type (and should be the last catch if you have several)int printf(char *, ...)
means a function takes a variable argument list, which entirely disables type-checking of arguments and is easy to get wrong (but occasionally useful)template <typename... TypePack>
means a template accepts a variable type list, which is very useful for metaprogramming but completely out of scope here#define DEBUG(str, ...)
is a variadic macro, analogous to the variable-argument functionFunction-level
try
/catch
blocks are a way of wrapping the whole function body in an exception handler. So, here, the main function block is inside thetry { ... }
.IIRC this was introduced specifically to allow constructors to wrap their initializer lists with a
try
/catch
, to handle exceptions thrown from subobject constructors.Eg. (motivating case)
Note that there is no other way to catch exceptions thrown from base class or member subobject constructors, because they'll always do at least default construction before your constructor body starts, even if you omit the initializer list.