120

Possible Duplicate:
catch exception by pointer in C++

I always catch exceptions by value. e.g

try{
...
}
catch(CustomException e){
...
}

But I came across some code that instead had catch(CustomException &e) instead. Is this a)fine b)wrong c)a grey area?

Community
  • 1
  • 1
Mr. Boy
  • 60,845
  • 93
  • 320
  • 589
  • Note that the correct reference is constant too: `catch(CustomException const &e)`... – Alexis Wilke Feb 07 '15 at 01:27
  • 8
    Should not be marked as duplicate -- catching exception by ptr is different than catching by reference or value. – wcochran Feb 10 '17 at 20:23
  • Closely related and useful : [why-catch-an-exception-as-reference-to-const](https://stackoverflow.com/questions/2145147/why-catch-an-exception-as-reference-to-const) – Rick Sep 19 '18 at 04:22

4 Answers4

177

The standard practice for exceptions in C++ is ...

Throw by value, catch by reference

Catching by value is problematic in the face of inheritance hierarchies. Suppose for your example that there is another type MyException which inherits from CustomException and overrides items like an error code. If a MyException type was thrown your catch block would cause it to be converted to a CustomException instance which would cause the error code to change.

Patrik
  • 2,695
  • 1
  • 21
  • 36
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 7
    To this I would add: catch by const reference. Unfortunately you can throw a const object and catch it with a non-const reference. To avoid this silent "casting away" of const, always catch a const reference, and ensure your exception types have const-correct accessors. – Daniel Earwicker Mar 26 '10 at 10:01
  • 28
    @Danial Earwicker: Why is it "unfortunate" that you can catch via an non-const reference? The exception object is always copied so whatever 'object' you throw, you can't affect the original from any catch block as the 'object' thrown was really just an initializer. There's no casting away of const; exception objects are always non-const, non-volatile. Allowing a catch via non-const reference enables intermediate catch blocks to add information to the exception. It's not commonly used but it's there if you need it. – CB Bailey Mar 26 '10 at 10:06
  • Can you provide a reference please, if you want the accepted answer :) – Mr. Boy Mar 26 '10 at 10:07
  • 2
    @John: Chapter 15 Exceptions, specifically 15.3 (exception handling) describes how the catch parameter is initialized from the exception object. Where the parameter is a class type (rather than a reference) it is initialized via a copy-constructor. – CB Bailey Mar 26 '10 at 10:12
  • 5
    @Daniel: to clarify Charles (and deliver to your inbox), the exception object you can catch and rethrow is by definition a temporary. The argument to `throw` should be on the stack and should be destroyed as the first order of business of unwinding. `throw new` is an error. – Potatoswatter Mar 26 '10 at 10:55
  • 4
    @Charles - You're right, it's not really casting away of const. I guess I think of it in the same terms as a temporary being passed to a method by non-const reference, which is banned elsewhere in the language to avoid attempts to mutate a temporary via the reference (when the mutation is going to be discarded anyway). But as you say, you might want to deliberately mutate the exception and then `throw;` which makes it visible elsewhere (thus breaking my analogy). – Daniel Earwicker Mar 26 '10 at 10:59
  • 1
    What if I don't need the exception value i.e. `catch(CustomException)`. Should I also use reference i.e. `catch(CustomException&)` ? – CITBL May 22 '20 at 08:48
36

Catching by value will slice the exception object if the exception is of a derived type to the type which you catch.

This may or may not matter for the logic in your catch block, but there is little reason not to catch by const reference.

Note that if you throw; without a parameter in a catch block, the original exception is rethrown whether or not you caught a sliced copy or a reference to the exception object.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • 8
    I'm not familiar with the term *slice* in this context. – Keith Pinson Nov 27 '12 at 16:59
  • 10
    I think "slice" is a term that people who are used to reference-passing languages like to use. The idea is you "slice off" part of the object if you assign a derived object to its base type, which to me seems like a misleading way to look at it because what is actually happening is that in the base class's copy assignment operator `base &operator=(const base &other)` the derived object is being implicitly converted to a `base &` reference, so the assignment treats the derived class the same as the base class. there is no magic slicing-up or transferring stuff, you are calling a function – Injektilo May 16 '13 at 08:30
  • @Injektilo I think *slice* here is mostly concerned about *virtual functions*. You use a base class reference to catch a derived class exception object, so dynamically binding can be useful here. For catch by value, base class object lose derived class details, for catch by reference, derived class information is merely hidden. – Rick Sep 19 '18 at 03:16
16

Unless you want to fiddle with the exception, you should usually use a const reference: catch (const CustomException& e) { ... }. The compiler deals with the thrown object's lifetime.

Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
2

in (CustomException e) new object of CustomException is created... so it's constructor will be called while in (CustomException &e) it will just the reference... not new object is created and no constructor will be called... so formal is little bit overhead... later is better to use...

Mihir Mehta
  • 13,743
  • 3
  • 64
  • 88
  • In the reference scenario, how is the memory of e released? If e is in the stack, the catch block becomes non sense? – Charlie Oct 18 '18 at 01:34