Topic: try and non-compound statements


Author: v.Abazarov@comAcast.net ("Victor Bazarov")
Date: Sun, 15 Feb 2004 21:32:05 +0000 (UTC)
Raw View
"Alan Meyer" <ameyer2@yahoo.com> wrote...
>
> ""Pilhofer, Frank"" <fpilhofe@mc.com> wrote in message
> news:C72E341DF733CD42A5523C584505E75408BDC761@ad-email1.ad.mc.com...
> > ...
> > Now I continue to find myself in the situation where I want to construct
> > an element, handle its exceptions, and then continue using that element.
> > The limitation to a compound-statement, with its corresponding lifecycle
> > issues doesn't make this easy, because in the code
> >
> >   try {
> >     std::string foo ("bar");
> >   } // some handlers
> >
> > the string of course doesn't exist beyond the try-block.
>
> Here's one way to do it with the existing standard:
>
>     std::string *foo;
>     try {
>         foo = new std::string ("bar");
>     }
>     catch (...) {}
>     // Now we can refer to *foo, foo->... or whatever
>
> foo is defined outside the try block but, because it is a
> pointer and not an object, the constructor is not invoked
> at the point of definition.
>
> That's not as nice as what you propose because it
> forces you as the programmer to do your own delete(),
> but it does get around the scoping problem.

Why not use an auto_prt<string>, then?  No need to 'delete'...

Victor

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: fp@fpx.de (Frank Pilhofer)
Date: Mon, 16 Feb 2004 03:27:03 +0000 (UTC)
Raw View
Alberto Barbati <AlbertoBarbati@libero.it> wrote:

 All right. I see that my problem statement was poorly phrased, and I
was misunderstood by some posters. I am not trying to access partially
constructed objects, i.e. after a constructor raised an exception.

>
>  In fact you can, although the syntax is bit cumbersome:
>  I agree it's ugly, especially because the catch-handlers of the
>  construction statement are physically far from the statement itself.
>

 Yes. This is the situation that I was trying to address: handle an
exception during construction locally. Continue using the object only
if no exception was raised.

 The other option is the one outlined in Alan's post: construct the
object on the heap, using new: then the pointer can be defined
before the try statement and remains valid beyond the catch blocks.
I am asserting that the exception handlers do not allow the current
block's flow to continue (with an uninitialized pointer), but that
they either throw a (different?) exception, or return.

 Alberto's code fragment is of course the correct way to handle
exceptions during construction, with the mentioned drawbacks. I
share his opinion about its ugliness and was trying to come up with
a less ugly option, i.e. where the exception handling is closer to
the point of occurence.

 Frank

--
Frank Pilhofer  ...........................................  fp@fpx.de
I'm a pessimist so that I can be positively suprised by reality. - FP

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: fpilhofe@mc.com ("Pilhofer, Frank")
Date: Wed, 11 Feb 2004 15:59:22 +0000 (UTC)
Raw View
===================================== MODERATOR'S COMMENT:
 Since "finally" has been beaten to death here, followup posters please
consider limiting their remarks to the proposed construct.  Thanks.


===================================== END OF MODERATOR'S COMMENT
Hi,

[I know the FAQ suggests to read D&E first, but I don't have it around.
Is
there an online list of accepted/considered/rejected extensions? - FP]

According to the C++ standard, the syntax for "try" is

  try-block:
      "try" compound-statement handler-seq

Now I continue to find myself in the situation where I want to construct
an element, handle its exceptions, and then continue using that element.
The limitation to a compound-statement, with its corresponding lifecycle
issues doesn't make this easy, because in the code

  try {
    std::string foo ("bar");
  } // some handlers

the string of course doesn't exist beyond the try-block. So all you can
do is

  try {
    std::string foo ("bar");
    // use foo
  } // handle exceptions

At that point, you cannot know whether exceptions were raised in the
constructor, or while using the string.

So I wonder what would happen if the syntax of try-block were changed to
allow for non-compound statements (the "statement" rule), e.g.

  try
    std::string foo ("bar");
  catch (...) {}
  // use foo

This would allow to handle exceptions during construction separately.

Does this idea make sense? Or would the above be bad practice?

[While talking about exception handling, having a "finally" clause would
be nice. But I'm sure I'm not the first to suggest it.]

Frank

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: v.Abazarov@comAcast.net ("Victor Bazarov")
Date: Wed, 11 Feb 2004 17:29:56 +0000 (UTC)
Raw View
"Pilhofer, Frank" <fpilhofe@mc.com> wrote...
> [..]
> [I know the FAQ suggests to read D&E first, but I don't have it around.
> Is
> there an online list of accepted/considered/rejected extensions? - FP]
>
> According to the C++ standard, the syntax for "try" is
>
>   try-block:
>       "try" compound-statement handler-seq
>
> Now I continue to find myself in the situation where I want to construct
> an element, handle its exceptions, and then continue using that element.

I wonder how you use "that element" if it fails to construct...

> The limitation to a compound-statement, with its corresponding lifecycle
> issues doesn't make this easy, because in the code
>
>   try {
>     std::string foo ("bar");
>   } // some handlers
>
> the string of course doesn't exist beyond the try-block. So all you can
> do is
>
>   try {
>     std::string foo ("bar");
>     // use foo
>   } // handle exceptions
>
> At that point, you cannot know whether exceptions were raised in the
> constructor, or while using the string.

Aren't you supposed to distinguish those by catching different exceptions?

> So I wonder what would happen if the syntax of try-block were changed to
> allow for non-compound statements (the "statement" rule), e.g.
>
>   try
>     std::string foo ("bar");
>   catch (...) {}

catch(...) {} is really useless if you really need to

>   // use foo

Wouldn't 'foo' be out of scope here?  Just consider other places where
a single (non-compound) statement is allowed:

    if (condition)
        int a = 42;
    // a is not available.

So, to make it consistent, the scope of 'foo' would have to be limited
to the 'try' clause, no?

>
> This would allow to handle exceptions during construction separately.

Just keep the exceptions separate, and you'll be able to handle them
separately.

>
> Does this idea make sense? Or would the above be bad practice?

I'll leave it to experts to judge.

V

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: ahp6@email.byu.edu ("Adam H. Peterson")
Date: Thu, 12 Feb 2004 20:15:27 +0000 (UTC)
Raw View
> So I wonder what would happen if the syntax of try-block were changed to
> allow for non-compound statements (the "statement" rule), e.g.
>
>   try
>     std::string foo ("bar");
>   catch (...) {}
>   // use foo

I would prefer allowing an "else" clause at the end of the catch
sequence, where the else body is considered part of the scope of the
try, but if the same exception were to occur in the body, they wouldn't
be caught by the catch blocks, and you wouldn't have to resort to
exception tunneling or something.  Something like this:

try {
 C1 var1(blah);
 C2 var2(blah2);
 C3 var3(blah3);
} catch (std::range_exception) {
 whatever();
} else {
 var1.dosomething(var2,var3);
 // etc ...
}

I've run into this situation when I wanted to do exception translation,
but only for boost::bad_lexical_cast's that occurred in a construction.
  In my situation, I ended up with some boost::bad_lexical_cast's that
were spuriously translated, until I tunneled the exceptions after the
construction.  Needless to say, the constructs were not simple.

I'm not sure how feasible this is to implement, or to implement without
overhead.  But compiler implementers have worked some remarkable magic
before.

Adam H. Peterson

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Nicola.Musatti@ObjectWay.it (Nicola Musatti)
Date: Fri, 13 Feb 2004 14:38:01 +0000 (UTC)
Raw View
fpilhofe@mc.com ("Pilhofer, Frank") wrote in message news:<C72E341DF733CD42A5523C584505E75408BDC761@ad-email1.ad.mc.com>...
[...]
> Now I continue to find myself in the situation where I want to construct
> an element, handle its exceptions, and then continue using that element.
> The limitation to a compound-statement, with its corresponding lifecycle
> issues doesn't make this easy, because in the code
>
>   try {
>     std::string foo ("bar");
>   } // some handlers

If an exception were thrown during foo's construction, you can't trust
it to be in any useful state. Why do you want to use it, then?

> the string of course doesn't exist beyond the try-block. So all you can
> do is
>
>   try {
>     std::string foo ("bar");
>     // use foo
>   } // handle exceptions
>
> At that point, you cannot know whether exceptions were raised in the
> constructor, or while using the string.

If you need to distinguish, either throw different exceptions or use
different try blocks:

std::string foo ("bar");
try {
  This();
}
catch (...) {
}
try {
  That();
}
catch (...) {
}

Cheers,
Nicola Musatti

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: ameyer2@yahoo.com ("Alan Meyer")
Date: Fri, 13 Feb 2004 22:14:10 +0000 (UTC)
Raw View
""Pilhofer, Frank"" <fpilhofe@mc.com> wrote in message
news:C72E341DF733CD42A5523C584505E75408BDC761@ad-email1.ad.mc.com...
> ...
> Now I continue to find myself in the situation where I want to construct
> an element, handle its exceptions, and then continue using that element.
> The limitation to a compound-statement, with its corresponding lifecycle
> issues doesn't make this easy, because in the code
>
>   try {
>     std::string foo ("bar");
>   } // some handlers
>
> the string of course doesn't exist beyond the try-block.

Here's one way to do it with the existing standard:

    std::string *foo;
    try {
        foo = new std::string ("bar");
    }
    catch (...) {}
    // Now we can refer to *foo, foo->... or whatever

foo is defined outside the try block but, because it is a
pointer and not an object, the constructor is not invoked
at the point of definition.

That's not as nice as what you propose because it
forces you as the programmer to do your own delete(),
but it does get around the scoping problem.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: AlbertoBarbati@libero.it (Alberto Barbati)
Date: Sat, 14 Feb 2004 05:48:36 +0000 (UTC)
Raw View
Pilhofer, Frank wrote:
> The limitation to a compound-statement, with its corresponding lifecycle
> issues doesn't make this easy, because in the code
>
>   try {
>     std::string foo ("bar");
>   } // some handlers
>
> the string of course doesn't exist beyond the try-block. So all you can
> do is
>
>   try {
>     std::string foo ("bar");
>     // use foo
>   } // handle exceptions
>
> At that point, you cannot know whether exceptions were raised in the
> constructor, or while using the string.

In fact you can, although the syntax is bit cumbersome:

   try {
     std::string foo("bar");
     try {
        // use foo
     }
     catch( /* omitted */ ) // handle execeptions raised while using foo
     {/* omitted */ }
   }
   catch( /* omitted */ ) // handle exceptions raised during construction
   { /* omitted */ }

I agree it's ugly, especially because the catch-handlers of the
construction statement are physically far from the statement itself.
Moreover, an exception thrown while using foo might be caught
"involuntarily" by construction catch-handlers.

> So I wonder what would happen if the syntax of try-block were changed to
> allow for non-compound statements (the "statement" rule), e.g.
>
>   try
>     std::string foo ("bar");
>   catch (...) {}
>   // use foo

the main problem I see with this syntax is: what happens if an exception
is thrown and caught and the control reaches the end of the
corresponding handler?

Of course, the control cannot pass to the next statement, because foo
would be in scope but would not have been constructed. It also cannot
jump somewhere else because this syntax does not allow the programmer to
specify the destination of the jump (jumping to end of the current scope
would be very unintuitive IMHO).

The only solution I see is to rethrow the exception, in the same way it
is done with function-try-blocks of a constructor (15.3/16). Frankly, I
never encountered a piece of code that requires this construct, so I
don't know how this requirement may affect the usefulness of this syntax.

Alberto

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dave@boost-consulting.com (David Abrahams)
Date: Sat, 14 Feb 2004 22:33:39 +0000 (UTC)
Raw View
ameyer2@yahoo.com ("Alan Meyer") writes:

> Here's one way to do it with the existing standard:
>
>     std::string *foo;
>     try {
>         foo = new std::string ("bar");
>     }
>     catch (...) {}
>     // Now we can refer to *foo, foo->... or whatever
>
> foo is defined outside the try block but, because it is a
> pointer and not an object, the constructor is not invoked
> at the point of definition.
>
> That's not as nice as what you propose because it
> forces you as the programmer to do your own delete(),
> but it does get around the scoping problem.

??

Before the catch(...) block is entered, the compiler destroys the
pointer and any partially-constructed std::string object if an
exception is thrown during the new-expression.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]