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”?
There is, it just has the keyword
trybefore the opening brace, and somecatchblocks after the end ofmain.They’re keywords, not functions, and they’re part of main, despite the
trycoming 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/catchblocks 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.