What to throw?

Discussion in 'C++' started by Ken, Jun 11, 2004.

  1. Ken

    Ken Guest

    Hi. I know it is recommended that exceptions should be caught by
    reference, but are there recommendations for how an exception should
    be thrown? Or is it just a matter of throwing a type that is
    compatiple with the catch. If that is the case, I suppose that if you
    are catching a reference to exception e, the exception being thrown
    better be an instance of e or a reference to an instance of e (ie., if
    you threw a pointer to e and caught a reference to e, the compiler
    would generate an error).

    Thanks for any clarification and/or correction,

    Ken
    Ken, Jun 11, 2004
    #1
    1. Advertising

  2. Ken wrote:
    > Hi. I know it is recommended that exceptions should be caught by
    > reference, but are there recommendations for how an exception should
    > be thrown? Or is it just a matter of throwing a type that is
    > compatiple with the catch. If that is the case, I suppose that if you
    > are catching a reference to exception e, the exception being thrown
    > better be an instance of e or a reference to an instance of e (ie., if
    > you threw a pointer to e and caught a reference to e, the compiler
    > would generate an error).


    You got the compatibility bit correctly. But just like in the rest
    of the language, "compatible" (or, correctly, "convertible") is more
    than just "the same". You can throw a object of a class derived
    from what you're going to catch by reference, for example.

    Also, the compiler shouldn't generate an error if you throw a pointer
    when trying to catch a reference. Somebody else might be expecting
    that pointer. You will likely get "uncaught exception" during run-
    time.

    ------------------------------------ example
    struct A {};
    struct B : A {};

    void foo() { throw B(); }
    void bar() {}

    int main() {
    try {
    foo();
    }
    catch (A&) {
    bar(); // you should end up here during execution
    }
    return 0;
    }

    ------------------------------------ another example:
    struct A {};
    struct B : A {};

    void foo() { throw new B(); }
    void bar() {}

    int main() {
    try {
    foo();
    }
    catch (A&) {
    bar(); // maybe somebody will throw a reference...
    }
    catch (A*) {
    bar(); // you should end up here because it's really a B*
    }
    return 0;
    }
    --------------------------------------

    HTH

    Victor
    Victor Bazarov, Jun 11, 2004
    #2
    1. Advertising

  3. Ken

    Ken Guest

    Victor Bazarov <> wrote in message news:<zqqyc.1265$>...
    Thanks so much for the examples!

    Just one follow-up: In the example below, let's say I replaced foo
    with:

    void foo()
    {
    B *myB;
    myB = new B();
    throw *myB;
    }

    Would this get caught by the reference catch (as opposed to the
    pointer)? If so, does this mean that the copy made for the throw
    would be a copy of the B instance as opposed to a copy of the pointer?
    If so, I'm wondering if this is what I really need to do to avoid a
    memory leak:

    void foo()
    {
    B *myB;
    myB = new B();
    throw *myB;
    delete myB;
    }

    On the otherhand, I'm thinking that the best way to do this is:

    void foo()
    {
    B myB;
    throw myB;
    }

    My assumption is that this, too, would get caught by the reference
    catch statement. Is this correct?

    Also, are there any advantages to throwing a pointer instead? Looking
    at all this, it seems to me like a general rule of thumb would be to
    just throw by value and catch by reference. Does this seem right?

    Thanks again for any input!

    Ken


    >
    > ------------------------------------ another example:
    > struct A {};
    > struct B : A {};
    >
    > void foo() { throw new B(); }
    > void bar() {}
    >
    > int main() {
    > try {
    > foo();
    > }
    > catch (A&) {
    > bar(); // maybe somebody will throw a reference...
    > }
    > catch (A*) {
    > bar(); // you should end up here because it's really a B*
    > }
    > return 0;
    > }
    > --------------------------------------
    >
    > HTH
    >
    > Victor
    Ken, Jun 12, 2004
    #3
  4. "Ken" <> wrote...
    > Victor Bazarov <> wrote in message

    news:<zqqyc.1265$>...
    > Thanks so much for the examples!
    >
    > Just one follow-up: In the example below, let's say I replaced foo
    > with:
    >
    > void foo()
    > {
    > B *myB;
    > myB = new B();
    > throw *myB;
    > }
    >
    > Would this get caught by the reference catch (as opposed to the
    > pointer)?


    Of course! The type of *myB is l-value of B, and as such can be bound
    to B&.

    > If so, does this mean that the copy made for the throw
    > would be a copy of the B instance as opposed to a copy of the pointer?


    There is no copy made for the throw. Why would there be?

    > If so, I'm wondering if this is what I really need to do to avoid a
    > memory leak:
    >
    > void foo()
    > {
    > B *myB;
    > myB = new B();
    > throw *myB;
    > delete myB;


    This is unreachable code. You will need to do "delete (&<caught_ref>)"
    whe you catch the object.

    > }
    >
    > On the otherhand, I'm thinking that the best way to do this is:
    >
    > void foo()
    > {
    > B myB;
    > throw myB;


    Or, simply

    throw B(); // no need to declare the local object

    > }
    >
    > My assumption is that this, too, would get caught by the reference
    > catch statement. Is this correct?


    I believe so.

    >
    > Also, are there any advantages to throwing a pointer instead? Looking
    > at all this, it seems to me like a general rule of thumb would be to
    > just throw by value and catch by reference. Does this seem right?


    Throwing a pointer does indeed seem unnecessary. However, if you
    want to be simple you can always do

    ...
    throw "such and such error";

    ...
    catch (char const* errormsg) // catching a pointer
    {
    cerr << errormsg;
    ...
    }

    V
    Victor Bazarov, Jun 12, 2004
    #4
  5. Ken

    Ken Guest

    "Victor Bazarov" <> wrote in message news:<r0Eyc.73993$3x.32729@attbi_s54>...
    >
    > > If so, does this mean that the copy made for the throw
    > > would be a copy of the B instance as opposed to a copy of the pointer?

    >
    > There is no copy made for the throw. Why would there be?
    >


    I believe that C++ creates a temporary copy of the exception object
    being thrown.

    See http://www.devx.com/tips/Tip/12707. This says that:

    "...when an exception is thrown, the mechanism first searches for an
    appropriate handler in the current scope. If such handler does not
    exist, all local objects are destroyed, the exception object itself is
    copied on the stack of the function that is higher in the calling
    chain, and only then is the current scope exited."

    So behind the scenes, it is a copy of the exception object that goes
    the next level up.

    - Ken
    Ken, Jun 14, 2004
    #5
  6. Ken wrote:
    >
    > "Victor Bazarov" <> wrote in message news:<r0Eyc.73993$3x.32729@attbi_s54>...
    > >
    > > > If so, does this mean that the copy made for the throw
    > > > would be a copy of the B instance as opposed to a copy of the pointer?

    > >
    > > There is no copy made for the throw. Why would there be?
    > >

    >
    > I believe that C++ creates a temporary copy of the exception object
    > being thrown.
    >


    It may, but it doesn't have to. Temporaries may be optimised away by
    the compiler, though you cannot make much use of that fact. In
    particular, the object thrown must be still destructible and
    copy-constructible; also, you cannot rely on the object that you catch
    (even if by reference) being the same as the one thrown.

    With every compiler I have, when catching by reference, no copies are
    created. If I try catching by value rather than by reference, a
    temporary for the catch statement is copy-constructed, but I believe
    it too is allowed to be eliminated if it is const.


    > See http://www.devx.com/tips/Tip/12707. This says that:
    >
    > "...when an exception is thrown, the mechanism first searches for an
    > appropriate handler in the current scope. If such handler does not
    > exist, all local objects are destroyed, the exception object itself is
    > copied on the stack of the function that is higher in the calling
    > chain, and only then is the current scope exited."
    >


    The stack is only guaranteed to be unwound if an appropriate handler
    is found in some enclosing scope. If not, it may or may not be
    unwound (and, accordingly, local objects may or may not be destructed)
    before terminate() is called.


    Denis
    Denis Remezov, Jun 14, 2004
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    1
    Views:
    816
  2. Kerri
    Replies:
    2
    Views:
    12,999
    Kevin Spencer
    Oct 27, 2003
  3. PrashanthNagaraj
    Replies:
    2
    Views:
    1,735
    Guest
    Nov 24, 2003
  4. Replies:
    15
    Views:
    7,495
    Roedy Green
    Sep 8, 2005
  5. Emanuele D'Arrigo

    To throw or to throw not?

    Emanuele D'Arrigo, Nov 14, 2008, in forum: Python
    Replies:
    6
    Views:
    312
    Emanuele D'Arrigo
    Nov 15, 2008
Loading...

Share This Page