-2

As mentioned in many previous answers, one should throw exceptions by value and catch them by reference ([A], [B]), such as

try {
    // throw std::exception();
}
catch(std::exception &e) {
    // handle exception
}

If you aren't going to make use of the exception itself (even though you should), this will however generate annoying "unused variable" warnings on compile. To avoid these, you can omit the parameter (e in the example above), at which point the catch block will trigger for the defined exception, but you won't have a variable to bother with.

However, almost every time I see this variable-less catch block, it is not declared by reference, but by value, as in

try {
    // throw std::exception();
}
catch(std::exception) {
    // handle exception
}

Even Our Lord and Savior has posted an answer this way (as have others). I did find one instance where references are used, though.

Since the variable isn't used, slicing isn't a problem, so there should be no effective difference between catching by value or by reference. However, why do people seemingly make a distinction between the with-variable and without-variable cases? Saving themselves the effort of adding that ampersand?

And, micro-optimizing as it may be (especially given how exceptional exceptions should be), doesn't the by-value case incur a casting cost (to see if the catch is appropriate for the thrown exception) mitigated when done by-reference?

Community
  • 1
  • 1
Wasabi
  • 2,879
  • 3
  • 26
  • 48

1 Answers1

0

Since the variable isn't used, slicing isn't a problem.

But you'd be forcing a copy in the case of a slice. Not that this is particularly problematic, since the exception ought to be on the rarely-taken code path.

However, if you were to re-throw the exception as a nested exception after a copy/slice then the final result might be surprising. e.g.:

struct E : std::runtime_error { using std::runtime_error::runtime_error; };

throw E("");

...

catch(std::runtime_error)
{
    std::throw_with_nested(std::logic_error(""));
} 



... further down the call stack...

catch(std::exception& e)
{
   // what did we actually catch? std::runtime error nested in a std::logic_error, or
  // E nested in a std::logic_error?
}
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142