catch exception by pointer in C++
Asked Answered
U

5

55

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;


}
Unsung answered 7/1, 2010 at 19:27 Comment(2)
You can not catch an exception by pointer. You can catch an exception that happens to be a pointer. The problem is that A and A* are two completely different types. If you throw a pointer to A then you can only catch value or reference. But it is a A* that you are catching by value or reference not the A.Microstructure
Also, since C++ compilers are permitted (though, not obligated) to elide the both copying processes, and as for the first of the copying (then throwing), if does not elide the copying then must to move the object instead of to copy.Poplar
R
88

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.

Russ answered 7/1, 2010 at 19:30 Comment(5)
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.Natishanative
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...Blum
I have seen code like const std::runtime_error err; throw err; am I correct assuming that this will not in fact be caught by reference (no conversion from const std::runtime_error& to std::runtime_error&)? This will therefore be caught by the runtime and presumably crash the program. Am I right?Fail
@SteveJessop That's a bright observation actually. I always worried about the std::string with exception description being copied in std::exception constructor. But if it fails to copy, I guess a reason-less std::bad_alloc is thrown anyway. Or maybe infinite recursion ensues :). Nicely thought out.Fail
@theswine No. When throwing a temporary object is made. [N3337, 15.1$3] Memory for it is allocated in unspecified way but not by operator new. [N3337, 151.$4] Whatevery you have in the throw expression is used to initialize that temporary object (either by copy - possibly elided - or by move). In your particular example a temporary object of std::runtime_error will be made and initialized by a copy from err. And then could be caught by both & and const&.Ancilla
S
17

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.

Spirketing answered 7/1, 2010 at 19:41 Comment(1)
I apologise if I come off as naive, but if we catch by reference, won't that be UB? Because the scope of that object that got created in the try block, is destroyed right? Or is it the case that, it allocates the return object dynamically, and then sends a reference to that?Tomikotomkiel
J
5

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.

Jell answered 7/1, 2010 at 19:43 Comment(0)
N
3

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...

Nicker answered 7/1, 2010 at 19:50 Comment(0)
M
0

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.

Manned answered 7/1, 2010 at 19:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.