11

Possible Duplicate:
Scope of exception object in C++

I have the following catch clauses:

catch(Widget w);
catch(Widget& w);

void passAndThrowWidget() {
          Widget localWidget;
      throw localWidget;
}

If we catch Widget object by value, compiler will make copy so when we throw exception, localWidget goes out of scope, and we don't see any issues.

If we catch widget object byreference, according to reference concept, "w" points to same local Widget instead of copy. But i have seen most of the exceptions are caught by references in C++. My question how this works as "localWidget" goes out of scope when exception is thrown and catch by referense points to object which is destroyed.

Thanks!

Community
  • 1
  • 1
venkysmarty
  • 11,099
  • 25
  • 101
  • 184

5 Answers5

9

throw expr; is similar to return expr; in that it uses copy initialization (list initialization is also possible with C++0x). But that's (mostly) syntax.

When it comes to semantics, then just as returning a value from a function returning a non-reference type is fine, so is throwing:

T f()
{
    // t is local but this is clearly fine
    T t;
    return t;

    // and so is this
    throw t;
}

Additionally it is unspecified whether what is returned or thrown is the result of the expression of the return or throw statement, or a copy (or move) from that expression.

The usual motivation for catching by reference has nothing to do with lifetime -- the lifetime of the thrown object is guaranteed to last at least as long as the catch clause. It is preferred because it allows exceptions to be designed and used polymorphically.

Luc Danton
  • 34,649
  • 6
  • 70
  • 114
3

The C++ runtime uses a memory location independent of the stack to store exception objects:

2.4.2 Allocating the Exception Object

Storage is needed for exceptions being thrown. This storage must persist while stack is being unwound, since it will be used by the handler, and must be thread-safe. Exception object storage will therefore normally be allocated in the heap, although implementations may provide an emergency buffer to support throwing bad_alloc exceptions under low memory conditions (see Section 3.3.1).

(from the C++ ABI for Itanium: Exception Handling)

So the reference you get when you "catch by reference" is a reference to that memory location, instead of a reference to a deallocated stack frame. This means exception objects are guaranteed to live long enough to be used by your exception handlers, even when obtained by reference. (They will probably be deallocated once you get out of the catch scope, though, so don't hold on to exception references.)

Community
  • 1
  • 1
zneak
  • 134,922
  • 42
  • 253
  • 328
2

Exceptions are the, well, exception to the rule of local scope:

try
{
    Widget w;
    throw w;
}
catch (const Widget& exc)
{
    // exc is a valid reference to the Widget
}

Even though local scope has ended, exceptions are handled in a special way, so what's thrown is still accessible.

Tim
  • 8,912
  • 3
  • 39
  • 57
  • +1, If it's true then a reasonable answer. – iammilind Jul 06 '11 at 05:08
  • Is `return w;` an exception too then? – Luc Danton Jul 06 '11 at 05:09
  • @Luc Danton, not in C++. Exceptions have a complex API to support them and force stack unwinding. A return statement merely hands back data to the previous frame, either by putting it in a register or on the stack on a location known to the caller; exceptions propagate in such a way that callers might even be completely unaware of them. There are other languages in which return values are exceptions though (or exceptions are return values, whichever floats your boat). – zneak Jul 06 '11 at 05:14
  • @Luc, oh, your comment suddenly makes more sense. I'm off to bed. – zneak Jul 06 '11 at 05:20
  • 2
    @Luc: No, if you return a local by reference, you get a dangling reference. Return values and thrown exceptions are very dissimilar in terms of lifetime. – Ben Voigt Jul 06 '11 at 05:22
  • Sorry Tim this is wrong. The reference `exc` will actually be a reference to an NEW object that was created using the copy constructor. Here's the code I used to figure that out, you can try running it yourself: http://pastebin.com/CAdnZEyA – David Grayson Jul 06 '11 at 05:30
0

In this line, you're creating a copy of your local object,

throw localWidget;

So, It doesn't refer to your local "localWidget" object but a copy of that object (called exception object) which is guaranteed to live until the exception is completely handled by the catch clause.

cpx
  • 17,009
  • 20
  • 87
  • 142
0

the instance that is thrown is copied when it is thrown. So you'll always get a copy anyhow.

it's better to catch by reference because the object that was thrown may have been polymorphic and you don't want to be relying on an 'error code' produced by a copy of a polymorphic class. The 'error code' wouldn't be specific to the derived class thrown at the throw point.

marinara
  • 538
  • 1
  • 5
  • 10