Question about exceptions.

Discussion in 'C++' started by LR, Sep 9, 2007.

  1. LR

    LR Guest

    Is this code valid? And if so, what should the output be?


    #include <iostream>
    #include <exception>

    int divide(const int a) {
    std::cout << "1 divide(" << a << ")" << std::endl;
    if(a == 0)
    throw std::exception();
    std::cout << "2 divide(" << a << ")" << std::endl;
    return 1/a;
    }

    class X {
    int k;
    public:
    X(const int a)
    try : k(divide(a))
    {
    std::cout << "X(" << a << ")" << std::endl;
    }
    catch(const std::exception &) {
    std::cout << "Caught by X(" << a << ")" << std::endl;
    }
    };

    void test1() {
    try {
    X a(1);
    X b(0);
    }
    catch(const std::exception &) {
    std::cout << "Caught by test1" << std::endl;
    }
    }

    void test2() {
    X a(1);
    X b(0);
    }


    int main() {
    test1();
    test2();
    }

    TIA.

    LR
     
    LR, Sep 9, 2007
    #1
    1. Advertising

  2. LR

    BobR Guest

    LR wrote in message...
    > Is this code valid? And if so, what should the output be?
    >
    > #include <iostream>
    > #include <exception>
    >
    > int divide(const int a) {
    > std::cout << "1 divide(" << a << ")" << std::endl;
    > if(a == 0)
    > throw std::exception();
    > std::cout << "2 divide(" << a << ")" << std::endl;
    > return 1/a;
    > }
    >
    > class X {
    > int k;
    > public:
    > X(const int a) try : k(divide(a)){
    > std::cout << "X(" << a << ")" << std::endl;
    > }
    > catch(const std::exception &) {
    > std::cout << "Caught by X(" << a << ")" << std::endl;


    // throw; // add this (after first test run)

    > }
    > };
    >
    > void test1() {
    > try {
    > X a(1);
    > X b(0);
    > }
    > catch(const std::exception &) {
    > std::cout << "Caught by test1" << std::endl;


    // throw; // add this (after 2nd test run, for main() )

    > }
    > }
    >
    > void test2() {
    > X a(1);
    > X b(0);
    > }
    >
    > int main() {
    > test1();
    > test2();
    > }
    >
    > TIA. LR


    Going through it by hand (my TestBench is temp off-line (busy with another
    project, different libraries) ).

    // void test1() { try { X a(1); ....
    1 divide(1)
    2 divide(1)
    X(1)
    // .... X b(0);
    1 divide(0)
    Caught by X(0) // X b invalid
    // void test2() { X a(1); .....
    1 divide(1)
    2 divide(1)
    X(1)
    // .... X b(0);
    1 divide(0)
    Caught by X(0) // X b invalid

    If you want to see the "Caught by test1" message, you should re-throw in the
    catch() in X Ctor (shown above).

    **But I'm guessing.**
    To be sure run the code with this main() as a safety net:

    int main() try {
    test1();
    test2();
    return 0;
    } // main()
    catch( std::exception const &) {
    std::cout<< "main caught exception"<<std::endl;
    return 1;
    } // main()
    catch( ... ) {
    std::cout<<"caught unknown"<<std::endl;
    return 1;
    } // main()

    See "Thinknog in C++" vol.2
    "Part 1: Building Stable Systems, 1: Exception Handling, Function-level
    try blocks" for more.

    --
    Bob R
    POVrookie
    Get "Thinking in C++", 2nd ed. Volume 1&2 by Bruce Eckel
    (available for free here. You can buy it in hardcopy too.):
    http://www.mindview.net/Books/TICPP/ThinkingInCPP2e.html
     
    BobR, Sep 9, 2007
    #2
    1. Advertising

  3. LR

    LR Guest

    BobR wrote:
    > LR wrote in message...
    >> Is this code valid? And if so, what should the output be?

    [snipped code I originally posted, that included some changes suggested
    by BobR]

    Ok, I snipped BobR's guess as to what the code would do, but it seemed
    like what I would expect.



    > If you want to see the "Caught by test1" message, you should re-throw in the
    > catch() in X Ctor (shown above).


    No. I put it in because it seemed like it was somehow being re-thrown
    in my code without my having to re-throw. Please see more below.


    > **But I'm guessing.**


    ;)

    [snipped code suggestions for main]


    I made some but not all of the changes you suggested. Here's the newer code.

    #include <iostream>
    #include <exception>

    int divide(const int a) {
    std::cout << "1 divide(" << a << ")" << std::endl;
    if(a == 0)
    throw std::exception();
    std::cout << "2 divide(" << a << ")" << std::endl;
    return 1/a;
    }

    class X {
    int k;
    public:
    X(const int a)
    try : k(divide(a))
    {
    std::cout << "X(" << a << ")" << std::endl;
    }
    catch(const std::exception &) {
    std::cout << "Caught by X(" << a << ")" << std::endl;
    }
    };

    void test1() {
    std::cout << "1 test1()" << std::endl;
    try {
    X a(1);
    X b(0);
    }
    catch(const std::exception &) {
    std::cout << "Caught by test1" << std::endl;
    }
    std::cout << "2 test1()" << std::endl;
    }

    void test2() {
    std::cout << "1 test2()" << std::endl;
    X a(1);
    X b(0);
    std::cout << "2 test2()" << std::endl;
    }


    int main() try {
    test1();
    test2();
    }
    catch(const std::exception &) {
    std::cout << "Caught std::exception & in main" << std::endl;
    }
    catch(...) {
    std::cout << "Caught unknown in main" << std::endl;
    }

    Here's the output with a comment added for the line I don't quite
    understand.
    -----------------------------------
    1 test1()
    1 divide(1)
    2 divide(1)
    X(1)
    1 divide(0)
    Caught by X(0)
    Caught by test1 // I don't quite get how we got caught a second time
    2 test1()
    1 test2()
    1 divide(1)
    2 divide(1)
    X(1)
    1 divide(0)
    Caught by X(0)
    Caught std::exception & in main // this is a little confusing too.
    --------------------------------------

    It's the second catch during test1() that I'm confused by. Is that some
    compiler magic? A bug? Undefined behavior?

    >
    > See "Thinknog in C++" vol.2
    > "Part 1: Building Stable Systems, 1: Exception Handling, Function-level
    > try blocks" for more.


    Thanks for the suggestion. This source (although I may be using a less
    recent copy of this text) says:

    "If an exception does occur, the contained object is not constructed, so
    it makes no sense to return to the code that created it. For this
    reason, the only sensible thing to do is to throw an exception in the
    function-level catch clause."

    That makes sense, because:
    SomeObject x; // If this throws, then...
    x.someMethod(); // ...what happens here?

    But the standard says in 15 note 3 (I copied this from the 2007 draft,
    but the text appears to be the same as the text in the standard.)

    "A function-try-block associates a handler-seq with the
    ctor-initializer, if present, and the function-body. An exception thrown
    during the execution of the initializer expressions in the
    ctor-initializer or during the execution of the functionbody transfers
    control to a handler in a function-try-block in the same way as an
    exception thrown during the execution of a try-block transfers control
    to other handlers."

    From my understanding, then we get caught and continue on. Perhaps
    there's another place in the standard that covers this situation?

    So I guess what my example code is doing is a good thing, but is that
    what the standard says should happen?


    > Get "Thinking in C++", 2nd ed. Volume 1&2 by Bruce Eckel
    > (available for free here. You can buy it in hardcopy too.):
    > http://www.mindview.net/Books/TICPP/ThinkingInCPP2e.html



    LR
     
    LR, Sep 10, 2007
    #3
  4. LR

    BobR Guest

    BobR wrote in message...
    >
    > See "Thinknog in C++" vol.2


    Hmmm, the Christmas version? Egg-Nog and brandy while reading?

    See "Thinking in C++"

    --
    Bob R
    POVrookie
     
    BobR, Sep 10, 2007
    #4
  5. LR

    BobR Guest

    LR wrote in message...
    > [snipped code suggestions for main]
    >
    > I made some but not all of the changes you suggested. Here's the newer

    code.
    >
    > #include <iostream>
    > #include <exception>
    >
    > int divide(const int a) {
    > std::cout << "1 divide(" << a << ")" << std::endl;
    > if(a == 0)
    > throw std::exception();
    > std::cout << "2 divide(" << a << ")" << std::endl;
    > return 1/a;
    > }
    >
    > class X {
    > int k;
    > public:
    > X(const int a)
    > try : k(divide(a))
    > {
    > std::cout << "X(" << a << ")" << std::endl;
    > }
    > catch(const std::exception &) {
    > std::cout << "Caught by X(" << a << ")" << std::endl;
    > }
    > };
    >
    > void test1() {
    > std::cout << "1 test1()" << std::endl;
    > try {
    > X a(1);
    > X b(0);
    > }
    > catch(const std::exception &) {
    > std::cout << "Caught by test1" << std::endl;
    > }
    > std::cout << "2 test1()" << std::endl;
    > }
    >
    > void test2() {
    > std::cout << "1 test2()" << std::endl;
    > X a(1);
    > X b(0);
    > std::cout << "2 test2()" << std::endl;
    > }
    >
    > int main() try {
    > test1();
    > test2();
    > }
    > catch(const std::exception &) {
    > std::cout << "Caught std::exception & in main" << std::endl;
    > }
    > catch(...) {
    > std::cout << "Caught unknown in main" << std::endl;
    > }
    >
    > Here's the output with a comment added for the line I don't quite
    > understand.
    > -----------------------------------
    > 1 test1()
    > 1 divide(1)
    > 2 divide(1)
    > X(1)
    > 1 divide(0)
    > Caught by X(0)
    > Caught by test1 // I don't quite get how we got caught a second time


    Not sure. I *think* it's because X is not constructed, and you can't return
    from an handler [1], the exception needs to follow the chain back to an
    handler.

    [1]
    class X {
    // ......
    catch( std::exception const &Se) {
    // return;
    // error: cannot return from a handler of a function-try-block of a
    constructor
    }

    > 2 test1()


    It got to here. The exception was handled by 'test1()' (not passed back to
    'main()').

    > 1 test2()
    > 1 divide(1)
    > 2 divide(1)
    > X(1)
    > 1 divide(0)
    > Caught by X(0)
    > Caught std::exception & in main // this is a little confusing too.


    There was no handler in 'test2()', so it looks for the next handler, which
    it finds in 'main()'.

    > --------------------------------------
    >
    > It's the second catch during test1() that I'm confused by. Is that some
    > compiler magic? A bug? Undefined behavior?


    Unless some expert comes by, we may both hang in darkness for the rest of
    our C++ lives! <G>

    >
    > "If an exception does occur, the contained object is not constructed, so
    > it makes no sense to return to the code that created it. For this
    > reason, the only sensible thing to do is to throw an exception in the
    > function-level catch clause."


    Some light!

    >
    > That makes sense, because:
    > SomeObject x; // If this throws, then...
    > x.someMethod(); // ...what happens here?
    >
    > But the standard says in 15 note 3 (I copied this from the 2007 draft,
    > but the text appears to be the same as the text in the standard.)
    >
    > "A function-try-block associates a handler-seq with the
    > ctor-initializer, if present, and the function-body. An exception thrown
    > during the execution of the initializer expressions in the
    > ctor-initializer or during the execution of the functionbody transfers
    > control to a handler in a function-try-block in the same way as an
    > exception thrown during the execution of a try-block transfers control
    > to other handlers."
    >
    > From my understanding, then we get caught and continue on. Perhaps
    > there's another place in the standard that covers this situation?


    Or, they left it to the implementation. Freedom.

    >
    > So I guess what my example code is doing is a good thing, but is that
    > what the standard says should happen?


    I always thought that once caught, the exception ceased, unless re-thrown.
    This seems to be an exceptional (pun?) situation. It kind-of makes sense.
    The X object failed to construct, so, the exception can't get fully handled
    there.
    ..
    --
    Bob R
    POVrookie
     
    BobR, Sep 10, 2007
    #5
  6. LR

    James Kanze Guest

    On Sep 10, 12:49 am, "BobR" <> wrote:
    > LR wrote in message...
    > > Is this code valid? And if so, what should the output be?


    [...]
    > > class X {
    > > int k;
    > > public:
    > > X(const int a) try : k(divide(a)){
    > > std::cout << "X(" << a << ")" << std::endl;
    > > }
    > > catch(const std::exception &) {
    > > std::cout << "Caught by X(" << a << ")" << std::endl;


    > // throw; // add this (after first test run)


    > > }
    > > };


    The throw isn't necessary; it's the default behavior here. See
    §15.3 ([Handling an Exception), para. 15: "The currently handled
    exception is rethrown if control reaches the end of a handler of
    the function-try-block of a constructor or destructor.
    Otherwise, a function returns when control reaches the end of a
    handler for the functiontryblock. Flowing off the end of a
    function-try-block is equivalent to a return with no value; this
    results in undefined behavior in a value-returning function."

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Sep 10, 2007
    #6
  7. LR

    LR Guest

    BobR wrote:
    > LR wrote in message...


    > I always thought that once caught, the exception ceased, unless re-thrown.


    That's what I thought too.


    > This seems to be an exceptional (pun?) situation.


    LOL. Thinknog in C++! ;)


    > It kind-of makes sense.
    > The X object failed to construct, so, the exception can't get fully handled
    > there.


    I'll almost agree there, I think it might depend on what code comes
    afterward. For example, if the unconstructed object is never used
    again, then maybe it's ok, and I think that might be possible, if for
    example the object is created using placement new. But I wish someone
    who knows for sure would say. Or maybe the standard needs a change?

    Thanks for your responses. Much appreciated.

    LR
     
    LR, Sep 10, 2007
    #7
  8. LR

    LR Guest

    James Kanze wrote:
    > On Sep 10, 12:49 am, "BobR" <> wrote:
    >> LR wrote in message...
    >>> Is this code valid? And if so, what should the output be?

    >
    > [...]
    >>> class X {
    >>> int k;
    >>> public:
    >>> X(const int a) try : k(divide(a)){
    >>> std::cout << "X(" << a << ")" << std::endl;
    >>> }
    >>> catch(const std::exception &) {
    >>> std::cout << "Caught by X(" << a << ")" << std::endl;

    >
    >> // throw; // add this (after first test run)

    >
    >>> }
    >>> };

    >
    > The throw isn't necessary; it's the default behavior here. See
    > §15.3 ([Handling an Exception), para. 15: "The currently handled
    > exception is rethrown if control reaches the end of a handler of
    > the function-try-block of a constructor or destructor.
    > Otherwise, a function returns when control reaches the end of a
    > handler for the functiontryblock. Flowing off the end of a
    > function-try-block is equivalent to a return with no value; this
    > results in undefined behavior in a value-returning function."


    Ah. Ok, thanks very much for that. Appreciated.

    LR
     
    LR, Sep 10, 2007
    #8
  9. LR

    BobR Guest

    James Kanze <> wrote in message...

    /* """

    On Sep 10, 12:49 am, "BobR" <> wrote:
    > LR wrote in message...
    > > Is this code valid? And if so, what should the output be?

    [...]
    > > class X {
    > > int k;
    > > public:
    > > X(const int a) try : k(divide(a)){
    > > std::cout << "X(" << a << ")" << std::endl;
    > > }
    > > catch(const std::exception &) {
    > > std::cout << "Caught by X(" << a << ")" << std::endl;


    > // throw; // add this (after first test run)


    > > }
    > > };


    The throw isn't necessary; it's the default behavior here. See
    §15.3 ([Handling an Exception), para. 15: "The currently handled
    exception is rethrown if control reaches the end of a handler of
    the function-try-block of a constructor or destructor.
    Otherwise, a function returns when control reaches the end of a
    handler for the functiontryblock. Flowing off the end of a
    function-try-block is equivalent to a return with no value; this
    results in undefined behavior in a value-returning function."

    """ */

    Yep. When I re-set my directories to normal, fired up my TestBench and
    plugged in LR's code, I realized what was happening (re-throw not needed).

    [ In the one place I do use such code, I re-throw my own runtime_error
    derived class, which informs, then shuts down the app. I think that's why I
    suggested that re-throw to LR when I was 'guessing'.]

    Thanks James.

    Good to have you back. :-}
    [ Good vacation? ]
    --
    Bob R
    POVrookie
     
    BobR, Sep 10, 2007
    #9
  10. LR

    BobR Guest

    LR wrote in message...
    >
    > > It kind-of makes sense.
    > > The X object failed to construct, so, the exception can't get fully

    handled
    > > there.

    >
    > I'll almost agree there, I think it might depend on what code comes
    > afterward. For example, if the unconstructed object is never used
    > again, then maybe it's ok, and I think that might be possible, if for
    > example the object is created using placement new.


    From 'TiCpp', vol.1 (chap.13, "placement new & delete"):

    "There's also a placement operator delete that is only called if a
    constructor for a placement new expression throws an exception (so that the
    memory is automatically cleaned up during the exception). The placement
    operator delete has an argument list that corresponds to the placement
    operator new that is called before the constructor throws the exception.
    This topic will be explored in the exception handling chapter in Volume 2. "

    --
    Bob R
    POVrookie
     
    BobR, Sep 10, 2007
    #10
    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. Elliot Rodriguez

    ASP.NET 1.1 - Exceptions and Request.Form Question

    Elliot Rodriguez, Mar 9, 2006, in forum: ASP .Net
    Replies:
    2
    Views:
    2,333
    Elliot Rodriguez
    Mar 9, 2006
  2. Ahmed Moustafa
    Replies:
    5
    Views:
    30,122
    Chris Smith
    Jul 14, 2004
  3. Paul Miller
    Replies:
    3
    Views:
    1,063
    Alex Martelli
    Nov 12, 2003
  4. Replies:
    3
    Views:
    634
    Sherm Pendley
    Apr 16, 2007
  5. Lie
    Replies:
    3
    Views:
    707
Loading...

Share This Page