I agree with this. Error handling code and exceptions are not mutually exclusive, and both have their benefits and drawbacks. Checking return codes in actually exceptional circumstances makes the code base almost unreadable, and exceptions work amazingly for this. On the other hand, using exceptions for common errors is both inefficient and ugly.
As an example of useful exceptions: malloc errors. In C, handling malloc failures is a nightmare. So much so that very few programs actually do it properly. The reason for that is that not only do you need to check the return code of malloc, you need to check the return code of every single function in your entire program that ever calls a malloc anywhere down the line.
So while this piece of code might be nice if you see it in one or two places:
int rc = fx ();
if (rc != 0) {
handle_error ();
}
Properly handling malloc errors means every single function call becomes a four line monstrosity, basically blowing up your code base by factor four and making the code much more difficult to read. Not to mention how insanely error prone it is to have to check the return code of every single function. When doing the wrong thing is so much easier than doing the correct thing, most people will do the wrong thing.