views:

677

answers:

5

Hi,

I found that there are three ways to catch an exception, what are the differences?

1) catch by value;

2) catch by reference;

3) catch by pointer;

I only know that catch by value will invoke two copies of the object, catch by reference will invoke one. So how about catch by pointer? When to use catch by pointer? In addition to throw an object, can I throw a pointer to an object like this?

class A {}

void f() {

  A *p = new A();
        throw p;


}
+19  A: 

The recommended way is to throw by value and catch by reference.

Your example code throws a pointer, which is a bad idea since you would have to manage memory at the catch site.

If you really feel you should throw a pointer, use a smart pointer such as shared_ptr.

Anyway, Herb Sutter and Alexei Alexandrescu explain that really well in their C++ Coding Standards book which I paraphrased.

See C++ Coding Standards: Throw by Value, Catch by Reference.

Gregory Pakosz
And if the reason you are throwing is because you are out of memory, then trying to allocating a new object to throw is not going to help.
George Edison
You'd either throw a pointer to A, or you'd throw std::bad_alloc, according to whether the A could be allocated. So at least you'd throw something...
Steve Jessop
@Gregory: Just a follow up on your flag... Accept rate is heavily cached, so it can take hours (rumored even to be days sometimes) for the displayed rate to accurately depict answers that a user has accepted very recently. I'm seeing a 100% accept rate for @skydoor now. Also see http://meta.stackoverflow.com/questions/34412/i-have-accepted-answers-for-all-my-questions-but-my-accept-rate-shows-86-closed
Bill the Lizard
indeed now it's 100%, thanks for the link on meta
Gregory Pakosz
A: 

There isn't really a good scenario for catching/throwing an exception by pointer. C++ semantics allow it, but it's not terribly useful, as most of the time you'll be throwing a temporary exception or string object.

However, some libraries (Boost.Graph does this, I believe) use throw to pass a return value back to the caller from a deeply recursed function; in a situation like this, the return value may be a pointer, so throwing a pointer would make sense.

dauphic
+7  A: 

Catch follows normal assignment compatibility rules, that is, if you throw a value, you can catch it as value or reference, but not as pointer; if you throw a pointer, you can catch it only as a pointer (or reference to a pointer...).

But it doesn't really make sense to throw pointers, it will only cause memory management headaches. Thus, you should, in general follow the rule throw by value, catch by reference, as explained by Gregory.

oefe
+1  A: 

Microsoft's MFC uses catch by pointer, but I think that was for compatibility with the compiler before try and catch were properly implemented; originally they used TRY and CATCH macros to simulate it. Each exception derives from CException, which has a method to determine whether the object needs to be deleted.

I wouldn't recommend that for any modern exception design. Catch by reference is the way to go.

Mark Ransom
+2  A: 

While it's possible to throw essentially any object of any type, there's little (if anything) to be gained by doing this. Dynamic allocation is useful primarily when an object needs to have a lifetime doesn't fit with automatic allocation -- i.e. you want its lifetime to be independent of normal program scope.

In the case of an exception object, however, that doesn't really make much sense. An exception object is normally only used inside of an exception handler, and you clearly want it to be destroyed when you exit the (last) handler for that exception.

There's also the fact that you generally want to keep exception handling code fairly simple. Just for example, if you're trying to report the free store/heap being exhausted or corrupt, trying to allocate your exception object off that exhausted/corrupt free store/heap usually won't work very well...

Jerry Coffin