Separating scope of try block?

Discussion in 'C++' started by Adam H. Peterson, Apr 5, 2006.

  1. Is there a way (idiom, construct, anything like that) to divorce the
    scope of a try block from the region of code where it will catch the
    exception? I mean, suppose I have a code snippet like this:

    try {
    Object o("data", 25, 16384);
    o.process(); // This may throw, but I don't want to handle it here.
    } catch (...) {
    std::cerr << "Couldn't construct the object" << std::endl;
    }

    Now, suppose the construction of o could fail with an exception, which
    is why we put it inside a try block. If this happens, we want to do
    something to handle it (in this case, notify the user and move on). But
    after it's constructed, we want to do something else with the object,
    and this stuff could also fail. But if it does, we want the exception
    to propagate outward to the surrounding handlers.

    Is there a way to trap exceptions from a constructor and not trap
    exceptions in the subsequent processing of the object?
    Adam H. Peterson, Apr 5, 2006
    #1
    1. Advertising

  2. Adam H. Peterson

    Ian Collins Guest

    Adam H. Peterson wrote:
    > Is there a way (idiom, construct, anything like that) to divorce the
    > scope of a try block from the region of code where it will catch the
    > exception? I mean, suppose I have a code snippet like this:
    >
    > try {
    > Object o("data", 25, 16384);
    > o.process(); // This may throw, but I don't want to handle it here.
    > } catch (...) {
    > std::cerr << "Couldn't construct the object" << std::endl;
    > }
    >
    > Now, suppose the construction of o could fail with an exception, which
    > is why we put it inside a try block. If this happens, we want to do
    > something to handle it (in this case, notify the user and move on). But
    > after it's constructed, we want to do something else with the object,
    > and this stuff could also fail. But if it does, we want the exception
    > to propagate outward to the surrounding handlers.
    >
    > Is there a way to trap exceptions from a constructor and not trap
    > exceptions in the subsequent processing of the object?


    Throw a different exception.

    --
    Ian Collins.
    Ian Collins, Apr 5, 2006
    #2
    1. Advertising

  3. Adam H. Peterson

    Phlip Guest

    Adam H. Peterson wrote:

    bool oIsConstructed = false;

    > try {
    > Object o("data", 25, 16384);


    oIsConstructed = true;

    > o.process(); // This may throw, but I don't want to handle it here.
    > } catch (...) {


    Always catch by name. ... is a hack that's only useful for debugging.

    if (oIsConstructed) throw;

    > std::cerr << "Couldn't construct the object" << std::endl;
    > }


    You were thinking too far inside the box. try catch is useful because our
    original old-fashioned techniques still also work.

    --
    Phlip
    http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
    Phlip, Apr 5, 2006
    #3
  4. Adam H. Peterson

    Phlip Guest

    Ian Collins wrote:

    > Throw a different exception.


    And note my post didn't think outside that box, either.

    Use my technique only if you can't change the source to Object, or if its
    constructor is deep and you don't know what it will throw.

    Alternately, put a try-catch block around the inside of the constructor
    (there's a special syntax for that), catch whatever it throws, and rethrow
    as Ian's special exception.

    --
    Phlip
    http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
    Phlip, Apr 5, 2006
    #4
  5. Phlip wrote:
    > Adam H. Peterson wrote:
    >>} catch (...) {

    >
    >
    > Always catch by name. ... is a hack that's only useful for debugging.


    The ellipsis was just to simplify the question. I didn't want answers
    directed towards exception translation or special casing, which I
    thought some might suggest if I named the exception. And, in
    "pseudo-code style," a reader could interpret the ellipsis as "whatever
    you want here."

    But the point is still good.

    >
    > if (oIsConstructed) throw;
    >
    >
    >> std::cerr << "Couldn't construct the object" << std::endl;
    >>}

    >
    >
    > You were thinking too far inside the box. try catch is useful because our
    > original old-fashioned techniques still also work.


    Thanks. I do tend to want language features to handle such complexity
    ad absurdium, and it's good to get a reminder that old-and-simple still
    usually works. This idiom appears to me to do what I want, and I can't
    think of a situation where it would be non-applicable.
    Adam H. Peterson, Apr 5, 2006
    #5
  6. Adam H. Peterson

    Guest

    Adam H. Peterson wrote:
    > Is there a way (idiom, construct, anything like that) to divorce the
    > scope of a try block from the region of code where it will catch the
    > exception? I mean, suppose I have a code snippet like this:
    >
    > try {
    > Object o("data", 25, 16384);
    > o.process(); // This may throw, but I don't want to handle it here.
    > } catch (...) {
    > std::cerr << "Couldn't construct the object" << std::endl;
    > }


    The first thing that comes to mind is a nested try..catch:

    try {
    Object o("data", 25, 16384);
    try {
    o.process();
    } catch (...) {
    std::cerr << "Couldn't process the object" << std::endl;
    }
    } catch (...) {
    std::cerr << "Couldn't construct the object" << std::endl;
    }

    Or, If your object has a defualt constructor and an operator=, you
    could write it like this:

    Object o;
    try {
    o = Object("data", 25, 16384); // Ugly; calls CTOR and operator=
    } catch (...) {
    std::cerr << "Couldn't construct the object" << std::endl;
    return;
    }
    try {
    o.process();
    } catch (...) {
    std::cerr << "Couldn't process the object" << std::endl;
    }

    Of course, my personal favorite would be to use a shared pointer; then
    you wouldn't need to add a default ctor and an operator=. It would
    look like this:

    shared_ptr<Object> o;
    try {
    o.reset(new Object("data", 25, 16384));
    } catch (...) {
    std::cerr << "Couldn't construct the object" << std::endl;
    return;
    }
    try {
    o->process();
    } catch (...) {
    std::cerr << "Couldn't process the object" << std::endl;
    }
    , Apr 5, 2006
    #6
  7. >The first thing that comes to mind is a nested try..catch:
    >
    >try {
    > Object o("data", 25, 16384);
    > try {
    > o.process();
    > } catch (...) {
    > std::cerr << "Couldn't process the object" << std::endl;
    > }
    >} catch (...) {
    >
    > std::cerr << "Couldn't construct the object" << std::endl;
    >
    >}


    Yeah, I don't care for this one because I want the exception(s) to
    propagate unless they're in the constructor. One of the big wins for
    exceptions is their ability to consolidate handling code and allow the
    handling policy to be global.

    >Or, If your object has a defualt constructor and an operator=, you
    >could write it like this:
    >
    >Object o;
    >try {
    > o = Object("data", 25, 16384); // Ugly; calls CTOR and operator=
    >} catch (...) {
    >
    > std::cerr << "Couldn't construct the object" << std::endl;
    > return;
    >}
    >
    >try {
    > o.process();
    >} catch (...) {
    >
    > std::cerr << "Couldn't process the object" << std::endl;
    >
    >}


    A bit inelegant, but it would do the job if you have a qualifying
    object and "return" will take you to the right place. I don't like the
    inefficiency of avoidable assignment, but I guess it would serve in a
    pinch.

    >Of course, my personal favorite would be to use a shared pointer; then
    >you wouldn't need to add a default ctor and an operator=. It would
    >look like this:
    >
    >shared_ptr<Object> o;
    >try {
    > o.reset(new Object("data", 25, 16384));
    >} catch (...) {
    >
    > std::cerr << "Couldn't construct the object" << std::endl;
    > return;
    >}
    >
    >try {
    > o->process();
    >} catch (...) {
    >
    > std::cerr << "Couldn't process the object" << std::endl;
    >
    >}


    I must confess I like this one least of all, as it involves using the
    heap. This introduces both inefficiency and the possibility of
    throwing on memory allocation.

    Thanks for the suggestions, though. I like the solution Philip
    provided best.
    Adam H. Peterson, Apr 5, 2006
    #7
  8. Adam H. Peterson

    Guest

    Adam H. Peterson wrote:
    > Thanks for the suggestions, though. I like the solution Philip
    > provided best.


    What's wrong with something like this instead?

    try
    {
    Object o("data", 25, 16384);
    o.process();
    }
    catch( MyProcessException &e )
    {
    std::cerr << "Couldn't process the object" << std::endl;
    }
    catch(...)
    {
    // Something else happened (constructor threw?) - pass it on
    throw;
    }

    Depending on what exactly you want to do, you may even be able to ommit
    the last catch block.

    Cheers,
    Andre
    , Apr 5, 2006
    #8
  9. Adam H. Peterson

    Gavin Deane Guest

    Adam H. Peterson wrote:
    > Thanks for the suggestions, though. I like the solution Philip
    > provided best.


    Did you see Phlip's reply to Ian Collins's suggestion?

    Unless there's some reason you can't be sure which exception will be
    thrown and you have to catch(...) (which isn't nice), or the two
    operations you are trying to distinguish between (constructing the
    Object and calling process on the Object) indicate failure by throwing
    the same type of exception (also not nice, since they seem like
    conceptually very different failures) then just use throw different
    exception types for different circumstances and catch only the types
    you can handle at each level.

    Gavin Deane
    Gavin Deane, Apr 5, 2006
    #9
  10. > Did you see Phlip's reply to Ian Collins's suggestion?

    Yes, I saw it. I am addressing the second of your situations, but it
    happens to handle the first as well. Specifically, I know what the
    constructor might throw and I know how I want to handle it. But for
    all I know, the rest of the processing might throw the same exception
    type and if so I don't want to handle it locally -- that's an
    unanticipated condition (within this block at least). So far Philip's
    solution fits what I want to do best. Ian's doesn't work, because it's
    not actually the constructor throwing the exception, it's one of the
    functions calling it. And I don't want to do exception translation
    because that just looks awkward when Philip's solution does the job so
    nicely.
    Adam H. Peterson, Apr 5, 2006
    #10
  11. >What's wrong with something like this instead?
    >
    >try
    >{
    > Object o("data", 25, 16384);
    > o.process();
    >}
    >
    >catch( MyProcessException &e )
    >{
    > std::cerr << "Couldn't process the object" << std::endl;
    >}
    >
    >catch(...)
    >{
    > // Something else happened (constructor threw?) - pass it on
    > throw;
    >
    >}


    Alas, the second catch block is purely redundant. And in this case,
    the MyProcessException will be handled locally whether Object() throws
    it or process() throws it. (Of course, I already knew how to do that.)
    Adam H. Peterson, Apr 5, 2006
    #11
  12. > And I don't want to do exception translation
    > because that just looks awkward when Philip's solution does the job so
    > nicely.


    More accurately, exception translation won't work in my case.
    process() happens to be a callback and Object is in a library I'm
    working on. Because process() is user supplied code, I don't know
    whether it will be instancing Objects of its own, and exception
    translation would still have both Object() and process() throwing the
    same exception.
    Adam H. Peterson, Apr 5, 2006
    #12
  13. Adam H. Peterson

    BobR Guest

    Phlip wrote in message <1_DYf.22943$>...
    >
    >Alternately, put a try-catch block around the inside of the constructor
    >(there's a special syntax for that), catch whatever it throws, and rethrow
    >as Ian's special exception.



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

    Chapter 1, "InitExcept.cpp" may be an example of 'that'.

    --
    Bob R
    POVrookie
    BobR, Apr 5, 2006
    #13
  14. Adam H. Peterson

    Kaz Kylheku Guest

    Adam H. Peterson wrote:
    > Is there a way (idiom, construct, anything like that) to divorce the
    > scope of a try block from the region of code where it will catch the
    > exception? I mean, suppose I have a code snippet like this:
    >
    > try {
    > Object o("data", 25, 16384);
    > o.process(); // This may throw, but I don't want to handle it here.
    > } catch (...) {
    > std::cerr << "Couldn't construct the object" << std::endl;
    > }


    [ snip ]

    > Is there a way to trap exceptions from a constructor and not trap
    > exceptions in the subsequent processing of the object?


    Object *ptr = 0;

    // trap construction exceptions, turning them into null pointer
    try {
    ptr = new Object("data", 25, 16384);
    } catch (...) {
    std::cerr << "Couldn't construct the object" << std::endl;
    }

    // If the object was made, process it without trapping exceptions.
    if (ptr != 0) {
    // process object: exceptions not trapped
    }

    // Finally, done with object, blow it away
    delete ptr;

    You can't get around dynamic allocation of the object, because if you
    construct the object in the lexical scope of the try in automatic
    storage, it will be destroyed when the try block finishes. Yet you want
    to keep the object around, so you can process it outside of the
    exception-handling region.
    Kaz Kylheku, Apr 6, 2006
    #14
  15. Adam H. Peterson

    Old Wolf Guest

    Adam H. Peterson wrote:

    > Is there a way (idiom, construct, anything like that) to divorce the
    > scope of a try block from the region of code where it will catch the
    > exception?


    std::auto_ptr<Object> optr;

    try {
    optr.reset( new Object(x) );
    }
    catch(...) {
    // handle error
    }

    Object &o = *optr.get();

    // do stuff with o, and don't mention optr again
    Old Wolf, Apr 6, 2006
    #15
    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. bienwell
    Replies:
    4
    Views:
    3,695
    bienwell
    May 27, 2005
  2. John Salerno
    Replies:
    20
    Views:
    807
    John Salerno
    Aug 11, 2006
  3. morrell
    Replies:
    1
    Views:
    925
    roy axenov
    Oct 10, 2006
  4. Fabio Z Tessitore

    who is simpler? try/except/else or try/except

    Fabio Z Tessitore, Aug 12, 2007, in forum: Python
    Replies:
    5
    Views:
    353
  5. Steve V
    Replies:
    6
    Views:
    227
    Steve V
    Apr 20, 2005
Loading...

Share This Page