Separating scope of try block?

  • Thread starter Adam H. Peterson
  • Start date
A

Adam H. Peterson

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?
 
I

Ian Collins

Adam said:
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.
 
P

Phlip

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

Phlip

Ian said:
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.
 
A

Adam H. Peterson

Phlip said:
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;




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

sshock

Adam said:
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;
}
 
A

Adam H. Peterson

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

int2str

Adam said:
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
 
G

Gavin Deane

Adam said:
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
 
A

Adam H. Peterson

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

Adam H. Peterson

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

Adam H. Peterson

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

BobR

Phlip wrote in message said:
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'.
 
K

Kaz Kylheku

Adam said:
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.
 
O

Old Wolf

Adam said:
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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top