Essentially, they should never be used at all. If you're going to have an unrecoverable error, it's trivial to design the system to exit without using exceptions anyway.
Probably the most useful side effect of exceptions is printing the stack trace, and that's not something where the overhead (both performance wise, and logical complexity wise) of exceptions is needed. And you should really be doing logging rather than relying on cryptic exception traces.
The one theoretical case where exceptions are sometimes argued to be superior is if you don't know what to do locally about an error, and you're hoping that a higher level part of the program might know how to recover. Classic example is a read error, and then asking the user to put a usb stick in.
But guess what? That's not how nontrivial programs work. The higher level simply can't know fully the effect of handling an exception that bubbled up, because the low level details that matter can and often do have unpredictable consequences in terms of program correctness, especially when you're reasoning at a higher level. When an exception is thrown, your program state is wonky. Only trivial programs are like the usb stick example. Real programs become subtly wrong if you try to recover a partially completed, partially incomplete, multi statge operation, especially if you're not the guy who wrote the code, but feel you're doing the right thing at a higher level.
Your greatest chance of correctly handling errors is a few lines above or below where the error actually occurs. Anything else sounds good but is worse.