开发者

C++ exceptions catch clause [duplicate]

开发者 https://www.devze.com 2023-03-17 07:58 出处:网络
This question already has answers here: Closed 11 years ago. Possible Duplicate: Scope of exception object in C++
This question already has answers here: Closed 11 years ago.

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!


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.


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


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.


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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号