Topic: A half serious proposal: overloaded destructors


Author: Nicola Musatti <Nicola.Musatti@R-it.it>
Date: Tue, 21 May 2002 18:35:59 GMT
Raw View

Allan W wrote:
>
> Nicola Musatti <objectway@divalsim.it> wrote
[...]
> > Normal activity can be handled by applying the RAII idiom. On the other
> > hand it is not currently possible to know within a destructor whether it
> > was called during the normal flow of execution or during stack
> > unwinding, so rollback must be called explicitly (you can switch things
> > around so that rollback is called in the destructor, but one of commit
> > and rollback must be called explicitly).
>
> I think it makes sense to make commit() explicit -- you know when your
> normal processing is done, and adding a commit() there seems natural.
> Plus, you only need to code it in one place, making most of what you
> say below irrelevant.

I tend to agree. I only just realized that the message you replied to is
missing one half of my argument! More later.

[...]
> > void exception_handler() {
> >   try {
> >     throw;
> >   }
> >   catch ( ExceptionA & a ) {
> >   // (A)
> >   }
> >   catch ( Exception & b ) {
> >   // (B)
> >   }
> > }
[...]
>
> Try this alternative then:
>
>     try {
>         try {
>             // Whatever...
>             tran.commit(); // If this needs to be explicit
>         } catch(...) {
>             // Something went wrong. If rollback() needs to
>             // be explicit, do it here -- then re-throw to
>             // perform more explicit error-checking.
>             tran.rollback(); // Something went wrong
>             throw;
>         }
>     }
>     catch ( ExceptionA & a ) {
>         // No need to call rollback
>     }
>     catch ( Exception & b ) {
>         // No need to call rollback
>     }
>     catch ( ... ) {
>         // No need to call rollback
>     }

Your example is perfect where the handling of commit/rollback is
concerned. The only advantage my exception_handler() has is that it lets
you separate the commit/rollback part from the exception management part
where I would expect reporting (to the user or the developer) would be
handled. This is the part of the argument that was missing from my
previous message. Some blunder, given that this reporting part was the
original motivation for my proposal.

> > My proposal solves this problem in a safer and more object oriented way;
> > the transaction class would become:
> >
> > class Transaction {
> >   public:
> >     Transaction() : { open(); }
> >     ~Transaction() { commit(); }
> >     ~Transaction(ExceptionA & a) { rollback(); /* handle a */ }
> >     ~Transaction(ExceptionB & b) { rollback(); /* handle b */ }
> >     void commit() { /* ... */ }
> >     void rollback() { /* ... */ }
> > };
> >
> > It remains to be established whether we want to introduce a special
> > notation analogous the catch(...), as ~Transaction(...), or if the
> > parameterless destructor should be called in this case.
>
> This is a big change. It doesn't seem compelling to me since we have
> viable alternatives today -- but then, I haven't read the whole
> thread (54 messages and growing!), so I might have missed something
> that would change my mind.

Actually I agree with you. I believe that wanting to change the language
just to solve the problem at hand is a serious conceptual mistake, which
is why I consider this proposal only "half serious". However from the
length of the thread I draw the impression that there's a feeling around
that exception management is an area of the language that needs to
evolve, even though there is little agreement on how. On the other hand
nobody wrote that my proposal is the one, true solution. Rats :-)

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: xleobx@qmailcomq.com
Date: Wed, 22 May 2002 20:07:07 GMT
Raw View
Nicola Musatti <Nicola.Musatti@r-it.it> wrote:

> xleobx@qmailcomq.com wrote:
> [...]
>> >From doing what? The contract for f(), as written, is to be only called
>> from within a catch block, and for that catch block - not to have throw;
>> after f() had been called. What's so dangerous? IMHO, it is as dangerous
>> as dereferencing a pointer without comparing it to 0 - if it is not
>> supposed to be 0 by contract, it is ok.

> In my opinion the danger stems from the fact that this is a very unusual
> situation: I'm convinced that very few people realize that "throw;"
> statements do not have to be physically contained in a catch block, so
> it's quite possible that the function's contract be misunderstood. While

This is subjective. I do not equate a possibility of confusion to danger.

> I couldn't hold it against a junior (well, even not so junior)
> programmer not being aware of this, I certainly would eat alive any
> programmer not checking pointers where they need to :-)

I certainly would eat alive any programmer checking pointers where they
were told (by contract) that they do not need to. :-)

 Leo

--
Omit x's and q's to reply.

---
[ 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 <Nicola.Musatti@R-it.it>
Date: Wed, 15 May 2002 16:43:22 GMT
Raw View

"Hillel Y. Sims" wrote:
>
> Couldn't you just do it all this way?
>
> class Transaction {
>       bool done;
>    public:
>       Transaction() : done(false) { open(); }
>       ~Transaction() { if (!done) rollback(); }
>       void commit() { done = true; /* ... */ }
>       void rollback() { done = true; /* ... */ }
> };

You omitted this part of my previous message:

    ~Transaction(ExceptionA & a) { rollback(); /* handle a */ }
    ~Transaction(ExceptionB & b) { rollback(); /* handle b */ }
                                                       ^
                 This is the problem I'm also trying to solve.

>
> try {
>   Transaction t;
>   // whatever
>   t.commit();  // explicit commit!
> }
> catch (ExceptionA& a) {
>   // handle error only
>   // no need to rollback
> }
> catch (ExceptionB& b) {
>   // handle error only
>   // no need to rollback
> }
> // no need at all for dangerous/undesirable catch(...)

With my solution I can avoid repeating *also* the above catch clauses,
without recurring to the dangerous "throw in the try block" trick.

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: Robert Klemme <bob.news@gmx.net>
Date: Wed, 15 May 2002 17:58:04 GMT
Raw View
hello nicola,

thank you for the lengthy elaboration.  please see my comments
below.

Nicola Musatti schrieb:
> Alright. There are (at least) two aspects to exception handling which
> require intercepting an active exception: one is performing local error
> related actions, such as rollback of transactional operations, and the
> other is manipulation of the exception object, possibly to supply it
> with information on the local context.

as far as i can see the rest of your posting deals with item one,
"rollback of transactional operations".

regarding item two, "manipulation of the exception object", i
think this is the wrong way to go.  rather exceptions should be
caught and maybe included in another exception that is thrown
from the handler.  as discussed in comp.object in two different
threads recently, declaring an exception of an underlying
application layer breaks encapsulation.  so you have to
catch-retrhow anyway to hide underlying layers from a package's
clients.

> In my opinion the currently
> available mechanisms make it difficult to design a well structured
> solution to the combined problems.

disagree.  see below.

> Normal activity can be handled by applying the RAII idiom. On the other
> hand it is not currently possible to know within a destructor whether it
> was called during the normal flow of execution or during stack
> unwinding,

in this case this is not needed as i try to demonstrate.  in
which cases do you need it really?

> so rollback must be called explicitly (you can switch things
> around so that rollback is called in the destructor, but one of commit
> and rollback must be called explicitly).
[snip]
> Transaction::rollback() must be called at points (A), (B) and (C). A
> couple of times two many for what is conceptually a single call. You can
> eliminate the extra calls only if you assume that either all caught
> exceptions will descend from the same base class or that you are not
> interested in the exception object.

there is an obvious third solution that you mentioned already:
switch it so the destructor invokes rollback().  why?  there is
only one exit from a successfull operation but several exits (via
the catch blocks) in case of error.  i prefer to explicitely
commit a transaction if all went well anyway and in this case
your multiple invokation problem is solved with this easily.

and you can even spare the "done" flag if you let the destructor
invoke rollback() always.  i think, that's the most reasonable
approach since it makes commit explicit and undo implicit -
especially when there are errors.  i find this simpler, cleaner
and more robust.

// my version
class Transaction {
  public:
    Transaction() { open(); }
    ~Transaction() { rollback(); }
    void commit() { /* ... */ }
    void rollback() { /* ... */ }

  private:
    void open();
};

> In this way you can separate exception object manipulation from
> transaction cleanup. However I can't say I like to populate my
> application with functions that have to be called within catch blocks
> and cause the application to crash if you call them elsewhere.

agree.

> It remains to be established whether we want to introduce a special
> notation analogous the catch(...), as ~Transaction(...), or if the
> parameterless destructor should be called in this case.
>
> I hope this was clearer.

well, i'm still missing an example where only your solution would
help.  as a rule of thumb i would solve problems at hand with
what is there instead of augmenting the language with new syntax
and semantic.  in this case it's easy without your suggestion as
i hope to have demonstrated.

regards

 robert

---
[ 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: xleobx@qmailcomq.com
Date: Wed, 15 May 2002 21:25:14 GMT
Raw View
Nicola Musatti <Nicola.Musatti@r-it.it> wrote:


> With my solution I can avoid repeating *also* the above catch clauses,
> without recurring to the dangerous "throw in the try block" trick.

Why do you keep calling it "the dangerous trick"? It is perfectly legal,
AFAICRTS.

 Leo

---
[ 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: "Hillel Y. Sims" <usenet@phatbasset.com>
Date: Thu, 16 May 2002 11:50:33 GMT
Raw View
"Nicola Musatti" <Nicola.Musatti@R-it.it> wrote in message
news:3CE22451.FF0C81DD@R-it.it...
>
>
> "Hillel Y. Sims" wrote:
> >
> > class Transaction {
> >       bool done;
> >    public:
> >       Transaction() : done(false) { open(); }
> >       ~Transaction() { if (!done) rollback(); }
> >       void commit() { done = true; /* ... */ }
> >       void rollback() { done = true; /* ... */ }
> > };
>
> You omitted this part of my previous message:
>
>     ~Transaction(ExceptionA & a) { rollback(); /* handle a */ }
>     ~Transaction(ExceptionB & b) { rollback(); /* handle b */ }
>                                                        ^
>                  This is the problem I'm also trying to solve.
>

Yes, I omitted that because I don't think it is really needed - the rollback
is implicit in my version for all exceptional destructions. You must perform
explicit commit (which seems like the most reasonable semantics to me for
commit/rollback-type code anyhow), in which case there is no need to provide
for explicit rollback in multiple exit paths. As far as error-handling
concerns,

try {
  Transaction t;
  // do stuff
  t.commit();
}
catch (ExceptionA& a) {
  // handle a
}
catch (ExceptionB& b) {
  // handle b
}

> With my solution I can avoid repeating *also* the above catch clauses,
> without recurring to the dangerous "throw in the try block" trick.

Your special destructor functions do not really avoid repeating the catch
clauses, since you are attempting to do the same error handling in both of
them too; in fact you repeat "rollback()" twice, but you don't need explicit
rollback at all when you use explicit non-exceptional commit instead. As far
as having multiple catch blocks, you can use the "try {throw;} catch (etc)"
technique (which is not unsafe when done from a normal catch block) to
consolidate error-handling into one function anyhow.

try {
  Transaction t;
  // do stuff
  t.commit();
}
catch (TransExceptionBase&) {
  handle_trans_exceptions();
}

void handle_trans_exceptions()
{
  try {
    throw;
  }
  catch (ExceptionA& a) {
    // handle a
  }
  catch (ExceptionB& b) {
    // handle b
  }
}

(I thought it was the going idea that error-handling is best handled on a
procedural, not per-object, basis? Did I misinterpret something?)

hys

--
Hillel Y. Sims
hsims AT factset.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                       ]





Author: Nicola Musatti <Nicola.Musatti@R-it.it>
Date: Thu, 16 May 2002 17:13:33 GMT
Raw View

xleobx@qmailcomq.com wrote:
>
> Nicola Musatti <Nicola.Musatti@r-it.it> wrote:
>
> > With my solution I can avoid repeating *also* the above catch clauses,
> > without recurring to the dangerous "throw in the try block" trick.
>
> Why do you keep calling it "the dangerous trick"? It is perfectly legal,
> AFAICRTS.

What happens if you call the following function outside a catch block?

void f() {
  try { throw; }
  catch (...) {}
}

How can you keep people from doing it?

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: xleobx@qmailcomq.com
Date: Thu, 16 May 2002 13:34:46 CST
Raw View
Nicola Musatti <Nicola.Musatti@r-it.it> wrote:

>> > With my solution I can avoid repeating *also* the above catch clauses,
>> > without recurring to the dangerous "throw in the try block" trick.
>>
>> Why do you keep calling it "the dangerous trick"? It is perfectly legal,
>> AFAICRTS.

> What happens if you call the following function outside a catch block?

> void f() {
>   try { throw; }
>   catch (...) {}
> }

terminate() is called.

> How can you keep people from doing it?

>From doing what? The contract for f(), as written, is to be only called
from within a catch block, and for that catch block - not to have throw;
after f() had been called. What's so dangerous? IMHO, it is as dangerous
as dereferencing a pointer without comparing it to 0 - if it is not
supposed to be 0 by contract, it is ok.

 Leo

---
[ 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 <Nicola.Musatti@R-it.it>
Date: Thu, 16 May 2002 19:07:53 GMT
Raw View

"Hillel Y. Sims" wrote:
>
> "Nicola Musatti" <Nicola.Musatti@R-it.it> wrote in message
> news:3CE22451.FF0C81DD@R-it.it...

[...]
> As far as error-handling concerns,
>
> try {
>   Transaction t;
>   // do stuff
>   t.commit();
> }
> catch (ExceptionA& a) {
>   // handle a
> }
> catch (ExceptionB& b) {
>   // handle b
> }
>
> > With my solution I can avoid repeating *also* the above catch clauses,
> > without recurring to the dangerous "throw in the try block" trick.
>
> Your special destructor functions do not really avoid repeating the catch
> clauses, since you are attempting to do the same error handling in both of
> them too; in fact you repeat "rollback()" twice,

This can be avoided by designing a class hyerarchy appropriately, even
though it might prove overkill.

> but you don't need explicit
> rollback at all when you use explicit non-exceptional commit instead. As far
> as having multiple catch blocks, you can use the "try {throw;} catch (etc)"
> technique (which is not unsafe when done from a normal catch block) to
> consolidate error-handling into one function anyhow.

This is exactly what is dangerous: you have a function that can only be
used in the "exceptional" context of catch clauses.

[...]
> (I thought it was the going idea that error-handling is best handled on a
> procedural, not per-object, basis? Did I misinterpret something?)

Is it better or is it just that there is no alternative?

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: Allan_W@my-dejanews.com (Allan W)
Date: Thu, 16 May 2002 20:55:18 GMT
Raw View
Nicola Musatti <objectway@divalsim.it> wrote
> There are (at least) two aspects to exception handling which
> require intercepting an active exception: one is performing local error
> related actions, such as rollback of transactional operations, and the
> other is manipulation of the exception object, possibly to supply it
> with information on the local context. In my opinion the currently
> available mechanisms make it difficult to design a well structured
> solution to the combined problems.
>
> As an example of the first problem consider a transactional operation
> which we might model as follows:
>
> class Transaction {
>   bool done;
>   public:
>     Transaction() : done(false) { open(); }
>     ~Transaction() { if ( ! done ) commit(); }
>     void commit() { done = true; /* ... */ }
>     void rollback() { done = true; /* ... */ }
> };
>
> Normal activity can be handled by applying the RAII idiom. On the other
> hand it is not currently possible to know within a destructor whether it
> was called during the normal flow of execution or during stack
> unwinding, so rollback must be called explicitly (you can switch things
> around so that rollback is called in the destructor, but one of commit
> and rollback must be called explicitly).

I think it makes sense to make commit() explicit -- you know when your
normal processing is done, and adding a commit() there seems natural.
Plus, you only need to code it in one place, making most of what you
say below irrelevant.

> Consider the following try/catch block:
>
> try {
> // whatever
> }
> catch ( ExceptionA & a ) {
> // (A)
> }
> catch ( Exception & b ) {
> // (B)
> }
> catch ( ... ) {
> // (C)
> }
>
> Transaction::rollback() must be called at points (A), (B) and (C). A
> couple of times two many for what is conceptually a single call. You can
> eliminate the extra calls only if you assume that either all caught
> exceptions will descend from the same base class or that you are not
> interested in the exception object. This may not be acceptable if, as
> assumed above, you need to manipulate the thrown objects; moreover, do
> we really want to give up static type checking for exceptions?
>
> One possible solution is to define a handler function as follows:
>
> void exception_handler() {
>   try {
>     throw;
>   }
>   catch ( ExceptionA & a ) {
>   // (A)
>   }
>   catch ( Exception & b ) {
>   // (B)
>   }
> }
>
> This can (must, actually) be called within the catch(...) block of the
> original statement and lets us remove the other two catch blocks.
>
> In this way you can separate exception object manipulation from
> transaction cleanup. However I can't say I like to populate my
> application with functions that have to be called within catch blocks
> and cause the application to crash if you call them elsewhere.

Try this alternative then:

    try {
        try {
            // Whatever...
            tran.commit(); // If this needs to be explicit
        } catch(...) {
            // Something went wrong. If rollback() needs to
            // be explicit, do it here -- then re-throw to
            // perform more explicit error-checking.
            tran.rollback(); // Something went wrong
            throw;
        }
    }
    catch ( ExceptionA & a ) {
        // No need to call rollback
    }
    catch ( Exception & b ) {
        // No need to call rollback
    }
    catch ( ... ) {
        // No need to call rollback
    }


> My proposal solves this problem in a safer and more object oriented way;
> the transaction class would become:
>
> class Transaction {
>   public:
>     Transaction() : { open(); }
>     ~Transaction() { commit(); }
>     ~Transaction(ExceptionA & a) { rollback(); /* handle a */ }
>     ~Transaction(ExceptionB & b) { rollback(); /* handle b */ }
>     void commit() { /* ... */ }
>     void rollback() { /* ... */ }
> };
>
> It remains to be established whether we want to introduce a special
> notation analogous the catch(...), as ~Transaction(...), or if the
> parameterless destructor should be called in this case.

This is a big change. It doesn't seem compelling to me since we have
viable alternatives today -- but then, I haven't read the whole
thread (54 messages and growing!), so I might have missed something
that would change my mind.

---
[ 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: "Hillel Y. Sims" <usenet@phatbasset.com>
Date: Fri, 17 May 2002 16:36:08 GMT
Raw View
"Nicola Musatti" <Nicola.Musatti@R-it.it> wrote in message
news:3CE3AACF.B8AFFE02@R-it.it...
>
> This can be avoided by designing a class hyerarchy appropriately, even
> though it might prove overkill.
>
Yes, see "explicit commit / implicit rollback" in the last few messages. :-)

>
> This is exactly what is dangerous: you have a function that can only be
> used in the "exceptional" context of catch clauses.

<quote>
<xleobx@qmailcomq.com> wrote in message
news:mRSE8.7635$T_.179068@iad-read.news.verio.net...
> >From doing what? The contract for f(), as written, is to be only called
> from within a catch block, and for that catch block - not to have throw;
> after f() had been called. What's so dangerous? IMHO, it is as dangerous
> as dereferencing a pointer without comparing it to 0 - if it is not
> supposed to be 0 by contract, it is ok.
</quote>

I agree. Many things are only appropriate to be used in certain contexts.

(Also, it seems less dangerous than having to put explicit rollback in
multiple places.)

>
> [...]
> > (I thought it was the going idea that error-handling is best handled on
a
> > procedural, not per-object, basis? Did I misinterpret something?)
>
> Is it better or is it just that there is no alternative?

I guess there's no alternative, but it just doesn't seem to be a big problem
to me either.. One line of explicit 'commit' makes the whole problem go
away.

thanks,
hys

--
Hillel Y. Sims
hsims AT factset.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                       ]





Author: Alexander Terekhov <terekhov@web.de>
Date: Mon, 20 May 2002 17:22:59 GMT
Raw View
"Hillel Y. Sims" wrote:
[...]
> I guess there's no alternative, but it just doesn't seem to be a big problem
> to me either.. One line of explicit 'commit' makes the whole problem go
> away.

That's quite correct. However, "one line" of explicit
"unwinding(this)" would make ZILLIONS explicit 'commit'
('bool commit_done', etc.) lines go away (*worldwide*,
I mean ;-)). Heck, think of global warming, etc.! ;-)

Oh, and, probably (unless I'm missing something) would
even FIX the standard ~sentry()-thing[1], already used
in "many" (only hell knows how many, I guess) places/
lines currently all over the blue planet Earth. Pretty
much the same applies to the rest of items on the "10
o'clock"-wish list, IMHO:

http://groups.google.com/groups?selm=3CC86F8C.94EFB52C%40web.de
http://groups.google.com/groups?selm=3CC97E16.3191C096%40web.de

regards,
alexander.

P.S. Leo, do you have some REAL email-address? ;-)

[1] http://groups.google.com/groups?selm=3CDBD7E2.EA14D26D%40web.de

---
[ 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 <Nicola.Musatti@R-it.it>
Date: Mon, 20 May 2002 17:47:46 GMT
Raw View

xleobx@qmailcomq.com wrote:
[...]
> >From doing what? The contract for f(), as written, is to be only called
> from within a catch block, and for that catch block - not to have throw;
> after f() had been called. What's so dangerous? IMHO, it is as dangerous
> as dereferencing a pointer without comparing it to 0 - if it is not
> supposed to be 0 by contract, it is ok.

In my opinion the danger stems from the fact that this is a very unusual
situation: I'm convinced that very few people realize that "throw;"
statements do not have to be physically contained in a catch block, so
it's quite possible that the function's contract be misunderstood. While
I couldn't hold it against a junior (well, even not so junior)
programmer not being aware of this, I certainly would eat alive any
programmer not checking pointers where they need to :-)

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: Nicola Musatti <objectway@divalsim.it>
Date: Mon, 13 May 2002 17:35:47 GMT
Raw View

Robert Klemme wrote:
[...]
> since i currently do not have a clear idea what might be the
> benefits of what you're proposing: would you mind coming up with
> a more adequate example?  thank you!

Alright. There are (at least) two aspects to exception handling which
require intercepting an active exception: one is performing local error
related actions, such as rollback of transactional operations, and the
other is manipulation of the exception object, possibly to supply it
with information on the local context. In my opinion the currently
available mechanisms make it difficult to design a well structured
solution to the combined problems.

As an example of the first problem consider a transactional operation
which we might model as follows:

class Transaction {
  bool done;
  public:
    Transaction() : done(false) { open(); }
    ~Transaction() { if ( ! done ) commit(); }
    void commit() { done = true; /* ... */ }
    void rollback() { done = true; /* ... */ }
};

Normal activity can be handled by applying the RAII idiom. On the other
hand it is not currently possible to know within a destructor whether it
was called during the normal flow of execution or during stack
unwinding, so rollback must be called explicitly (you can switch things
around so that rollback is called in the destructor, but one of commit
and rollback must be called explicitly).

Consider the following try/catch block:

try {
// whatever
}
catch ( ExceptionA & a ) {
// (A)
}
catch ( Exception & b ) {
// (B)
}
catch ( ... ) {
// (C)
}

Transaction::rollback() must be called at points (A), (B) and (C). A
couple of times two many for what is conceptually a single call. You can
eliminate the extra calls only if you assume that either all caught
exceptions will descend from the same base class or that you are not
interested in the exception object. This may not be acceptable if, as
assumed above, you need to manipulate the thrown objects; moreover, do
we really want to give up static type checking for exceptions?

One possible solution is to define a handler function as follows:

void exception_handler() {
  try {
    throw;
  }
  catch ( ExceptionA & a ) {
  // (A)
  }
  catch ( Exception & b ) {
  // (B)
  }
}

This can (must, actually) be called within the catch(...) block of the
original statement and lets us remove the other two catch blocks.

In this way you can separate exception object manipulation from
transaction cleanup. However I can't say I like to populate my
application with functions that have to be called within catch blocks
and cause the application to crash if you call them elsewhere.

My proposal solves this problem in a safer and more object oriented way;
the transaction class would become:

class Transaction {
  public:
    Transaction() : { open(); }
    ~Transaction() { commit(); }
    ~Transaction(ExceptionA & a) { rollback(); /* handle a */ }
    ~Transaction(ExceptionB & b) { rollback(); /* handle b */ }
    void commit() { /* ... */ }
    void rollback() { /* ... */ }
};

It remains to be established whether we want to introduce a special
notation analogous the catch(...), as ~Transaction(...), or if the
parameterless destructor should be called in this case.

I hope this was clearer.

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: "Hillel Y. Sims" <usenet@phatbasset.com>
Date: Tue, 14 May 2002 15:47:59 GMT
Raw View
Couldn't you just do it all this way?

class Transaction {
      bool done;
   public:
      Transaction() : done(false) { open(); }
      ~Transaction() { if (!done) rollback(); }
      void commit() { done = true; /* ... */ }
      void rollback() { done = true; /* ... */ }
};

try {
  Transaction t;
  // whatever
  t.commit();  // explicit commit!
}
catch (ExceptionA& a) {
  // handle error only
  // no need to rollback
}
catch (ExceptionB& b) {
  // handle error only
  // no need to rollback
}
// no need at all for dangerous/undesirable catch(...)

hys

"Nicola Musatti" <objectway@divalsim.it> wrote in message
news:3CDF9DAE.7B09DCC3@divalsim.it...
>
> class Transaction {
>   bool done;
>   public:
>     Transaction() : done(false) { open(); }
>     ~Transaction() { if ( ! done ) commit(); }
>     void commit() { done = true; /* ... */ }
>     void rollback() { done = true; /* ... */ }
> };
>
> Normal activity can be handled by applying the RAII idiom. On the other
> hand it is not currently possible to know within a destructor whether it
> was called during the normal flow of execution or during stack
> unwinding, so rollback must be called explicitly (you can switch things
> around so that rollback is called in the destructor, but one of commit
> and rollback must be called explicitly).
>
> Consider the following try/catch block:
>
> try {
> // whatever
> }
> catch ( ExceptionA & a ) {
> // (A)
> }
> catch ( Exception & b ) {
> // (B)
> }
> catch ( ... ) {
> // (C)
> }
>
> Transaction::rollback() must be called at points (A), (B) and (C). A
> couple of times two many for what is conceptually a single call. You can
> eliminate the extra calls only if you assume that either all caught
> exceptions will descend from the same base class or that you are not
> interested in the exception object. This may not be acceptable if, as
> assumed above, you need to manipulate the thrown objects; moreover, do
> we really want to give up static type checking for exceptions?
>
> One possible solution is to define a handler function as follows:
>
> void exception_handler() {
>   try {
>     throw;
>   }
>   catch ( ExceptionA & a ) {
>   // (A)
>   }
>   catch ( Exception & b ) {
>   // (B)
>   }
> }
>
> This can (must, actually) be called within the catch(...) block of the
> original statement and lets us remove the other two catch blocks.
>
> In this way you can separate exception object manipulation from
> transaction cleanup. However I can't say I like to populate my
> application with functions that have to be called within catch blocks
> and cause the application to crash if you call them elsewhere.
>
> My proposal solves this problem in a safer and more object oriented way;
> the transaction class would become:
>
> class Transaction {
>   public:
>     Transaction() : { open(); }
>     ~Transaction() { commit(); }
>     ~Transaction(ExceptionA & a) { rollback(); /* handle a */ }
>     ~Transaction(ExceptionB & b) { rollback(); /* handle b */ }
>     void commit() { /* ... */ }
>     void rollback() { /* ... */ }
> };
>
> It remains to be established whether we want to introduce a special
> notation analogous the catch(...), as ~Transaction(...), or if the
> parameterless destructor should be called in this case.
>
> I hope this was clearer.
>

--
Hillel Y. Sims
hsims AT factset.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                       ]





Author: Nicola Musatti <objectway@divalsim.it>
Date: Thu, 9 May 2002 18:45:09 GMT
Raw View

Robert Klemme wrote:
>
> how about:
>
> class Transaction {
>   bool success;
>   public:
>     Transaction() : success(false) { open(); }
>     ~Transaction() { if ( succes ) commit(); else rollback(); }
>
>    void setSuccess(bool s) { success = s; }
> };
>
> void foo() throws ArbitraryExceptions {
>   Transactin t;
>
>   // do stuff that can throw ArbitraryExceptions
>   t.setSuccess( true );
>
>   // automatic destruction doing commit() or rollback()
> }

This obviously works and there are different similar solution;
personally I think I'd prefer an explicit commit() with a possibly
implicit rollback(). Commit's success is marked as you did with a
boolean member, to be checked before rolling back in the destructor.

I realize that my example does not really convey the motivation for my
proposal, that is to provide an object oriented approach to exception
handling. The advantages would be a more generalized form of RAII,
capable of handling errors and not just being error neutral, and easier
factoring of generic aspects of error handling, like augmenting
exceptions with local context information.

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: Robert Klemme <robert.klemme@myview.de>
Date: Fri, 10 May 2002 15:26:47 GMT
Raw View

Nicola Musatti schrieb:
> This obviously works and there are different similar solution;

thanks.

> I realize that my example does not really convey the motivation for my
> proposal, that is to provide an object oriented approach to exception
> handling. The advantages would be a more generalized form of RAII,
> capable of handling errors and not just being error neutral, and easier
> factoring of generic aspects of error handling, like augmenting
> exceptions with local context information.

since i currently do not have a clear idea what might be the
benefits of what you're proposing: would you mind coming up with
a more adequate example?  thank you!

regards

 robert

--=20
Robert Klemme
software engineer
-------------------------------------------------------------------------=
-------
myview technologies GmbH & Co. KG
Lindberghring 1 ~ 33142 B=FCren ~ Germany
Fon: +49-2955-7433-20 Fax: +49-2955-7433-99
-------------------------------------------------------------------------=
-------

---
[ 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: xleobx@qmailcomq.com
Date: Thu, 2 May 2002 17:07:14 GMT
Raw View
Alexander Terekhov <terekhov@web.de> wrote:

>> What I want is simply something like
>>
>> catch(...) {
>>         cerr << "An unexpected exception with typeID " <<
>>         exception_type_info_stack.top.name() << " has been caught\n";
>> }
>>
>> Or, in the least, to pass the type_info into unexpected() and
>> terminate().

> Why do you need this (is this really better than complete
> core-/crash-dump-like things recorded at throw point)?

You never know what the 3rd-party/legacy software might do. In any case,
if the information is present, it should be possible to display it.

>> 2. At any point in the program the stack of in-flight exception
>> objects, including their typeids, is available for inspection
>> (and the stack top - for modification, with some restrictions).

> Yup, but why "stack top" only?

So that the type of an exception does not change as a result of handling
of _another_, nested, exception.

> Also, I'd add:

> 2a. At any point in the program the stack of CAUGHT exception
> objects, including their typeids, is available for inspection
> (?and modification?).

Right, although most of the functionality (except typeids in case of ...)
can be constructed using existing means.

>> I bet I missed something for which pre-ctors and post-dtors are needed.

> Basically the idea is that *each* class in the hierarchy
> of the most-derived (i.e. dynamic-type, the one we could
> instantiate) object can *optionally* have ONE post-ctor
> and *optionally* ONE pre-dtor. On construction, after the
> usual constructor invocation chain, post-constructors
> should fire (in the same order as constructor *bodies*;
> base classes first); THEY could then freely publish this,

What's wrong with

class C : public B {
 C(...) {
  ...
  finalize();
 }
 void finalize() {
  B::finalize();
  // whatever
 }
}

Except that the call to finalize() must be put manually into all the
ctors, and the order of calls to base class(es) in finalize() must
be manually synchronized with the hierarchy.

> (without any danger that some vf. callback could hit an
> "incomplete" object, start/join threads, etc) use/call "this"
> virtuals themself, query typeid/dynamic_cast -- FULLY use
> the polymorphic behavior.

This can be done after the opening brace of the most derived constructor.
Or  is there a catch?

> On destruction phase, basically
> "the same" stuff, but pre-destructors *first* (prior to
> destructors and in the same order).

Same here. Minor inconvenience compared to other things.

 Leo

---
[ 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: Alexander Terekhov <terekhov@web.de>
Date: Thu, 2 May 2002 17:07:27 GMT
Raw View
"Hillel Y. Sims" wrote:

[...RTTI/vtables...]

> > 1. Given a static type T or a type_info (that's my wish) of type T,
> > a way exists to find out whether throwing an instance of T from the
> > current dynamic scope will be caught, or result in unexpected(),
> > or in terminate().
>
> If static type checking,

No; "dynamic" checking.

> wouldn't that just imply compile-time ES checking?

Compile{-link}-time ES checking is completely different
"beast". It could indeed warn/help w.r.t. perhaps "missing"
catch-clauses, but that would NOT mean that ALL possibly
thrown exceptions should ALWAYS be caught -- there always
be UNEXPECTED exceptions only good (if thrown) to produce
a nice "core-dumped" message.

> (which might be cool, sure) If dynamic checking, see above.

See above what (what does this have to do with RTTI/vtables)?

> > 2. At any point in the program the stack of in-flight exception
> > objects, including their typeids, is available for inspection
> > (and the stack top - for modification, with some restrictions).
>
> I think there is really sort of only one current exception at any time
> (stack frame). Alexander Terekhov's trick of recursive throw/catch seems to
> show multiple exceptions active at one time, but (someone called it "abuse"
> of rules) I think there's still only really sort of one "active" at each
> stage -- if it ever escaped to an outer layer where the other exception was
> already active, the program would terminate. So c++ only wants to deal with
> one outstanding exception per stack frame (nesting is ok, but can't see
> outer layers)

Nobody's been arguing that C++ should want to deal
with multiple-all-flying-together exceptions! I've
been "arguing" all along that C++ should deal with
(read: provide access means):

1. <thread-specific> SINGLE STACK of exceptions [a) and b)
   COULD even be interleaved]:

      a) uncaught (in-flight) ones;

      b) caught-but-still-active (in the
         sense of being re-throwable).

2. <thread-specific> SINGLE STACK of objects under destruction due
   to unwinding caused by ALL those in-flight exceptions.

3. Mechanism for dynamic exception checking (expected_exception<T>()).

4. Better/easier to use local context RAII objects.

5. Better/easier to use means to exploit TRUE polymorphic behavior
   "under" construction and destruction -- pre/post stuff.

6. Get rid of USELESS and JUST-CONFUSING std::uncaught_exception().

> > 3. At any point in the program the stack of object pointers for which
> > the unwind dtors are currently being called is available for inspection.
>
> ??

see above (2.). ;-)

regards,
alexander.

---
[ 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: "Pavel Kuznetsov" <pavel@despammed.com>
Date: Thu, 2 May 2002 20:06:13 GMT
Raw View
Nicola Musatti (objectway@divalsim.it) wrote:

NM> In the specific context of stack unwinding I don't believe that
NM> destructors with multiple arguments should be allowed, because
NM> they wouldn't make sense.

There could be an idea that destructor with multiple parameters
is intended for handling any of exceptions of listed in parameter
list. And ellipsis destructor is perfectly fitting here.

NM> On the other hand if you accept Dave Harris's proposal from
NM> another subthread, multiple argument destructors could be
NM> used in explicit calls and in "finalization" lists, e.g.:

NM> ~Derived::Derived() : ~Base(someArgument) {}

It seems that those proposals are not mixing well.
Am I wrong about that?

--
Pavel

---
[ 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: John Nagle <nagle@animats.com>
Date: Mon, 6 May 2002 07:53:27 GMT
Raw View
     The real issue here is that a destructor can't
assume that the class invariant is true.

    John Nagle
    Animats

---
[ 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: "Hillel Y. Sims" <usenet@phatbasset.com>
Date: Wed, 1 May 2002 17:13:52 GMT
Raw View
<xleobx@qmailcomq.com> wrote in message
news:Lxly8.7185$T_.159121@iad-read.news.verio.net...
>
> catch(...) {
> cerr << "An unexpected exception with typeID " <<
> exception_type_info_stack.top.name() << " has been caught\n";
> }

Doesn't this require the type to have a vtable in order to pull out RTTI
information? "catch(...)" may catch types that do not have vtables.

>
> Or, in the least, to pass the type_info into unexpected() and
> terminate().

(same as above)

>
> 1. Given a static type T or a type_info (that's my wish) of type T,
> a way exists to find out whether throwing an instance of T from the
> current dynamic scope will be caught, or result in unexpected(),
> or in terminate().

If static type checking, wouldn't that just imply compile-time ES checking?
(which might be cool, sure) If dynamic checking, see above.

>
> 2. At any point in the program the stack of in-flight exception
> objects, including their typeids, is available for inspection
> (and the stack top - for modification, with some restrictions).

I think there is really sort of only one current exception at any time
(stack frame). Alexander Terekhov's trick of recursive throw/catch seems to
show multiple exceptions active at one time, but (someone called it "abuse"
of rules) I think there's still only really sort of one "active" at each
stage -- if it ever escaped to an outer layer where the other exception was
already active, the program would terminate. So c++ only wants to deal with
one outstanding exception per stack frame (nesting is ok, but can't see
outer layers)

>
> 3. At any point in the program the stack of object pointers for which
> the unwind dtors are currently being called is available for inspection.

??

hys

--
Hillel Y. Sims
hsims AT factset.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                       ]





Author: xleobx@qmailcomq.com
Date: Wed, 1 May 2002 21:08:13 GMT
Raw View
Hillel Y. Sims <usenet@phatbasset.com> wrote:

>> catch(...) {
>> cerr << "An unexpected exception with typeID " <<
>> exception_type_info_stack.top.name() << " has been caught\n";
>> }

> Doesn't this require the type to have a vtable in order to pull out RTTI
> information? "catch(...)" may catch types that do not have vtables.

Right... And how does that work, exactly?

>> 1. Given a static type T or a type_info (that's my wish) of type T,
>> a way exists to find out whether throwing an instance of T from the
>> current dynamic scope will be caught, or result in unexpected(),
>> or in terminate().

> If static type checking, wouldn't that just imply compile-time ES checking?
> (which might be cool, sure) If dynamic checking, see above.

The compiler may be allowed to optimize the check, but in general
even the static type checking cannot be done across compilation units.

>> 2. At any point in the program the stack of in-flight exception
>> objects, including their typeids, is available for inspection
>> (and the stack top - for modification, with some restrictions).

> I think there is really sort of only one current exception at any time
> (stack frame). Alexander Terekhov's trick of recursive throw/catch seems to
> show multiple exceptions active at one time, but (someone called it "abuse"

That was me.

> of rules) I think there's still only really sort of one "active" at each
> stage -- if it ever escaped to an outer layer where the other exception was

Right, but there may still be more than one in-flight _exception objects_,
as demonstrated by the example.

> already active, the program would terminate. So c++ only wants to deal with
> one outstanding exception per stack frame (nesting is ok, but can't see
> outer layers)

It may be argued one way or another; I tried to reformulate Alexander's
wishes in a more abstract form.

>> 3. At any point in the program the stack of object pointers for which
>> the unwind dtors are currently being called is available for inspection.

> ??

So a dtor or a function called from it is able to find out whether the
dtor is called as part of stack unwinding (and if yes, whether it is
the top-level unwinding or a nested unwinding - rollbacks may fail as well,
right?)

 Leo

---
[ 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: xleobx@qmailcomq.com
Date: Wed, 1 May 2002 22:59:08 GMT
Raw View
Nicola Musatti <objectway@divalsim.it> wrote:

> One solution to this problem could be the "throw in the try block"
> idiom, even though I'm not sure whether it's really supposed to work:

> try {
>   start_transaction();
>   commit();
> }
> catch(...) {
>   rollback();
>   handle_exceptions();
> }

> where

> void handle_exceptions() {
>   try {
>     throw;
>   }
>   catch (ExceptionA & a) {
>     // do something appropriate to ExceptionA
>   }
>   catch (ExceptionB & b) {
>     // do something appropriate to ExceptionB
>   }
>   catch (...) {
>     // is there anything you can do here?
>   }
> }

It is supposed to work by the lack of a mention otherwise in the standard,
and it does work.

 Leo

---
[ 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: xleobx@qmailcomq.com
Date: Wed, 8 May 2002 03:31:57 GMT
Raw View
John Nagle <nagle@animats.com> wrote:
>      The real issue here is that a destructor can't

Which class' destructor? The base one, or the derived one?

> assume that the class invariant is true.

The class invariant does not get violated by the mere entry into the
destructor, does it? And if it does not, a call to the finalizer
can be inserted at the beginning of the dtor's code.

 Leo

---
[ 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: Robert Klemme <robert.klemme@myview.de>
Date: Wed, 8 May 2002 16:08:30 GMT
Raw View
how about:

class Transaction {
  bool success;
  public:
    Transaction() : success(false) { open(); }
    ~Transaction() { if ( succes ) commit(); else rollback(); }

   void setSuccess(bool s) { success =3D s; }
};


void foo() throws ArbitraryExceptions {
  Transactin t;

  // do stuff that can throw ArbitraryExceptions
  t.setSuccess( true );

  // automatic destruction doing commit() or rollback()
}

regards

 robert

--=20
Robert Klemme
software engineer
-------------------------------------------------------------------------=
-------
myview technologies GmbH & Co. KG
Lindberghring 1 ~ 33142 B=FCren ~ Germany
Fon: +49-2955-7433-20 Fax: +49-2955-7433-99
-------------------------------------------------------------------------=
-------

---
[ 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: xleobx@qmailcomq.com
Date: Mon, 29 Apr 2002 18:28:38 GMT
Raw View
Alexander Terekhov <terekhov@web.de> wrote:

> xleobx@qmailcomq.com wrote:
> [...]
>>         Leo
>> missing typeid(exception) in catch(...).

> Perhaps this could help:

[skipped, it would not help]

> Or do you mean something (as it seems to me)
> LESS weird and MORE "generic" from future_std
> namespace: ;-)

What I want is simply something like

catch(...) {
 cerr << "An unexpected exception with typeID " <<
 exception_type_info_stack.top.name() << " has been caught\n";
}

Or, in the least, to pass the type_info into unexpected() and
terminate().

> (missing items from my new "10 o'clock"-wish list; just ideas ;-))
>
>  9. size_t caught_exception_scope() -> 0/scope;
>     ("throw;" -- re-throw is OK "if (caught_exception_scope())")

> 10. "caught_ex_ptr_or_ref<T>(size_t scope = 0)" (ref.version throws)
>    ("scope = 0" means "current"; in effect: caught_exception_scope());

Let's separate concepts from the implementation and reformulate the wishes:

1. Given a static type T or a type_info (that's my wish) of type T,
a way exists to find out whether throwing an instance of T from the
current dynamic scope will be caught, or result in unexpected(),
or in terminate().

2. At any point in the program the stack of in-flight exception
objects, including their typeids, is available for inspection
(and the stack top - for modification, with some restrictions).

3. At any point in the program the stack of object pointers for which
the unwind dtors are currently being called is available for inspection.

I bet I missed something for which pre-ctors and post-dtors are needed.

 Leo

---
[ 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@divalsim.it>
Date: Mon, 29 Apr 2002 18:30:00 GMT
Raw View

Pavel Kuznetsov wrote:
[...]
> I like this. I am just curious how to interpret destructors
> with several arguments, especially if proposed extention
> applies to ellipsis destructors.

In the specific context of stack unwinding I don't believe that
destructors with multiple arguments should be allowed, because they
wouldn't make sense. On the other hand if you accept Dave Harris's
proposal from another subthread, multiple argument destructors could be
used in explicit calls and in "finalization" lists, e.g.:

~Derived::Derived() : ~Base(someArgument) {}

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: Sean Parent <sparent@adobe.com>
Date: Mon, 29 Apr 2002 18:30:17 GMT
Raw View
in article 3CCD2EB3.C88D3AC9@divalsim.it, Nicola Musatti at
objectway@divalsim.it wrote on 4/29/02 4:44 AM:

> My attitude is more conservative: I don't believe that the semantics of
> stack unwinding should be modified except for the fact that the
> destructor becomes capable of accessing the exception object which
> caused its execution.

>> The case I would like to use this for is to "decorate" exception objects
>> with context information about what is currently happening.
>
> Exactly.

I think access to the exception should include being able to modify the
exception. You agree with the goal, but if there isn't a way to decorate an
exception that is in-flight if you can't throw a new exception. Without
this, you are forced to use try / catch to achieve this behavior. That is
the equivalent of forcing people to use try / catch for managing resources.
Ideally, try / catch is only used in cases where the propagation of they
exception may actually be halted.

I also think uncaught_exception() should be deprecated from the language
unless someone can tell me what useful information it provides.

It does not tell if a particular object is being unwound so it isn't useful
for commit / rollback transaction handling.

It does not tell you if you can call throw naked, in order to decode an
exception.

Changing the result to an int really doesn't provide any additional useful
information. Some of the information that Alexander is proposing I can see
being useful - although I'm not convinced of it's safety (and he seems not
to be convinced of the safety of mine).

In suedo code - my proposal would be the equivalent of:

{
Object object;
try
    {
    // Do stuff.
    }
catch (ExeptionType value)
    {
    object.~Object(value);
    throw;
    }
object.~Object();
}

It seems quite safe and flexible. A catching destructor could never be hit
for a heap allocated object, because heap allocated objects are not unwound.

Sean


--
Sean Parent
Sr. Computer Scientist II
Advanced Technology Group
Adobe Systems Incorporated
sparent@adobe.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                       ]





Author: Nicola Musatti <objectway@divalsim.it>
Date: Mon, 29 Apr 2002 18:30:07 GMT
Raw View

Dave Harris wrote:
[...]
> I see allowing destructors to take arguments as making the language more
> uniform. Every other kind of function can take arguments; destructors are
> currently a special case. It is an arbitrary and unnecessary limitation.
> To me, getting rid of that limitation makes the language simpler and
> easier to teach.

To me it's more a question of moving the distinction elsewhere. In
general you don't explicitly call destructors, so your mechanism is not
(= cannot be) general. You could provide arguments in your
pseudo-initialization list or in an explicit call following placement
new, but not in the general case. I cannot see how this makes the
language easier to teach.

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: Sean Parent <sparent@adobe.com>
Date: Mon, 29 Apr 2002 18:33:17 GMT
Raw View
in article 3CCD2EB3.C88D3AC9@divalsim.it, Nicola Musatti at
objectway@divalsim.it wrote on 4/29/02 4:44 AM:

> My attitude is more conservative: I don't believe that the semantics of
> stack unwinding should be modified except for the fact that the
> destructor becomes capable of accessing the exception object which
> caused its execution.

>> The case I would like to use this for is to "decorate" exception objects
>> with context information about what is currently happening.
>
> Exactly.

I think access to the exception should include being able to modify the
exception. You agree with the goal, but if there isn't a way to decorate an
exception that is in-flight if you can't throw a new exception. Without
this, you are forced to use try / catch to achieve this behavior. That is
the equivalent of forcing people to use try / catch for managing resources.
Ideally, try / catch is only used in cases where the propagation of they
exception may actually be halted.

I also think uncaught_exception() should be deprecated from the language
unless someone can tell me what useful information it provides.

It does not tell if a particular object is being unwound so it isn't useful
for commit / rollback transaction handling.

It does not tell you if you can call throw naked, in order to decode an
exception.

Changing the result to an int really doesn't provide any additional useful
information. Some of the information that Alexander is proposing I can see
being useful - although I'm not convinced of it's safety (and he seems not
to be convinced of the safety of mine).

In suedo code - my proposal would be the equivalent of:

{
Object object;
try
    {
    // Do stuff.
    }
catch (ExeptionType value)
    {
    object.~Object(value);
    throw;
    }
object.~Object();
}

It seems quite safe and flexible. A catching destructor could never be hit
for a heap allocated object, because heap allocated objects are not unwound.

Sean


--
Sean Parent
Sr. Computer Scientist II
Advanced Technology Group
Adobe Systems Incorporated
sparent@adobe.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                       ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Tue, 30 Apr 2002 18:43:46 GMT
Raw View
objectway@divalsim.it (Nicola Musatti) wrote (abridged):
> To me it's more a question of moving the distinction elsewhere. In
> general you don't explicitly call destructors, so your mechanism is not
> (= cannot be) general. You could provide arguments in your
> pseudo-initialization list or in an explicit call following placement
> new, but not in the general case. I cannot see how this makes the
> language easier to teach.

It's similar to passing extra arguments to operator++(). If we do ++x,
then there is no way to pass an argument, and if we do x++, an argument is
passed but we can't control what it is. However, if we write
x.operator++() we can put an argument in the brackets. (I don't recall
whether we can pass more than one; I hope we can.)

In the same way, the "delete p" syntax doesn't have a space for arguments,
but p->~X() does. I don't think this is difficult to teach because it is
kinda obvious from the syntactic form whether an argument-list is
possible.

To put it another way, I see "delete x" as not having an argument list,
and p->~X() has having an empty argument list. Whenever an empty argument
list is allowed, a non-empty one should also be allowed.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ 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: Alexander Terekhov <terekhov@web.de>
Date: Tue, 30 Apr 2002 18:51:34 GMT
Raw View
xleobx@qmailcomq.com wrote:
>
> Alexander Terekhov <terekhov@web.de> wrote:
>
> > xleobx@qmailcomq.com wrote:
> > [...]
> >>         Leo
> >> missing typeid(exception) in catch(...).
>
> > Perhaps this could help:
>
> [skipped, it would not help]
>
> > Or do you mean something (as it seems to me)
> > LESS weird and MORE "generic" from future_std
> > namespace: ;-)
>
> What I want is simply something like
>
> catch(...) {
>         cerr << "An unexpected exception with typeID " <<
>         exception_type_info_stack.top.name() << " has been caught\n";
> }
>
> Or, in the least, to pass the type_info into unexpected() and
> terminate().

Why do you need this (is this really better than complete
core-/crash-dump-like things recorded at throw point)?

> > (missing items from my new "10 o'clock"-wish list; just ideas ;-))
> >
> >  9. size_t caught_exception_scope() -> 0/scope;
> >     ("throw;" -- re-throw is OK "if (caught_exception_scope())")
>
> > 10. "caught_ex_ptr_or_ref<T>(size_t scope = 0)" (ref.version throws)
> >    ("scope = 0" means "current"; in effect: caught_exception_scope());
>
> Let's separate concepts from the implementation and reformulate the wishes:

OK.

> 1. Given a static type T or a type_info (that's my wish) of type T,
> a way exists to find out whether throwing an instance of T from the
> current dynamic scope will be caught, or result in unexpected(),
> or in terminate().

Yep.

> 2. At any point in the program the stack of in-flight exception
> objects, including their typeids, is available for inspection
> (and the stack top - for modification, with some restrictions).

Yup, but why "stack top" only?

Also, I'd add:

2a. At any point in the program the stack of CAUGHT exception
objects, including their typeids, is available for inspection
(?and modification?).

> 3. At any point in the program the stack of object pointers for which
> the unwind dtors are currently being called is available for inspection.

Yep.

> I bet I missed something for which pre-ctors and post-dtors are needed.

Basically the idea is that *each* class in the hierarchy
of the most-derived (i.e. dynamic-type, the one we could
instantiate) object can *optionally* have ONE post-ctor
and *optionally* ONE pre-dtor. On construction, after the
usual constructor invocation chain, post-constructors
should fire (in the same order as constructor *bodies*;
base classes first); THEY could then freely publish this,
(without any danger that some vf. callback could hit an
"incomplete" object, start/join threads, etc) use/call "this"
virtuals themself, query typeid/dynamic_cast -- FULLY use
the polymorphic behavior. On destruction phase, basically
"the same" stuff, but pre-destructors *first* (prior to
destructors and in the same order).

Also, I'd add:

4. Make RAII even less cumbersome; heck, why do we need to pass
ANYTHING to the "do/undo" local RAII objects -- everything is in
the local context already! So, why not just make it a-sort-of-
template thing?!

5. It seems to me that Sean needs something to "intercept"
exceptions in the d-tors. AFAICT, his catching (re-throw or
throw-something-else) d-tors DO INTERCEPT exceptions
(throw-something-else case) AND/OR even prompt unneeded/harmful
unwinding (e.g. re-throw case with no "real" catch handler
present at all) via "injecting" implicit "catch" clauses.
Or am I again missing something, Sean? Well, if someone really
need it, I'd probaly do it via yet another "replacing_throw
throw-expression;" sort-of new thing (to explicitly replace
some *expected* exception with a new one; completelly get rid
of old "uncaught"-but-expected one).

regards,
alexander.

---
[ 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@divalsim.it>
Date: Tue, 30 Apr 2002 18:51:42 GMT
Raw View

Sean Parent wrote:
[...]
> I think access to the exception should include being able to modify the
> exception. You agree with the goal, but if there isn't a way to decorate an
> exception that is in-flight if you can't throw a new exception. Without
> this, you are forced to use try / catch to achieve this behavior. That is
> the equivalent of forcing people to use try / catch for managing resources.
> Ideally, try / catch is only used in cases where the propagation of they
> exception may actually be halted.

It may not be evident in my initial example, but the main reason for my
proposal is actually to allow piggybacking of additional information
onto the current active exception from within a destructor called during
stack unwinding.

> I also think uncaught_exception() should be deprecated from the language
> unless someone can tell me what useful information it provides.
>
> It does not tell if a particular object is being unwound so it isn't useful
> for commit / rollback transaction handling.
>
> It does not tell you if you can call throw naked, in order to decode an
> exception.

My point is actually that you shouldn't need to do these things; I can't
help feeling that these manipulations are just clumsy workarounds for
badly designed programs. The solution to these problems should lie in
architecture, not in trying to find out what happened after the fact.

The only problem I personally have with the current try/catch mechanism
is that it makes it somewhat hard to build reusable error handling
solutions, due to its inherent stack oriented locality, and it is
towards solving this problem that I presented my proposal. By the way, I
feel that your example below illustrates my issues very well :-)

Consider:

try {
  start_transaction();
  // ...
  commit();
}
catch (ExceptionA & a) {
  rollback();
  // do something appropriate to ExceptionA
}
catch (ExceptionB & b) {
  rollback();
  // do something appropriate to ExceptionB
}
catch (...) {
  rollback();
}

Written in this way you have to repeat rollback in each catch block; not
only that but if you have to catch the same exception types and you want
to handle them exactly as you did here, but the transaction is
different, you have to either essentially repeat the code above or to
write a rather complicated wrapper.

One solution to this problem could be the "throw in the try block"
idiom, even though I'm not sure whether it's really supposed to work:

try {
  start_transaction();
  commit();
}
catch(...) {
  rollback();
  handle_exceptions();
}

where

void handle_exceptions() {
  try {
    throw;
  }
  catch (ExceptionA & a) {
    // do something appropriate to ExceptionA
  }
  catch (ExceptionB & b) {
    // do something appropriate to ExceptionB
  }
  catch (...) {
    // is there anything you can do here?
  }
}

[...]
>
> {
> Object object;
> try
>     {
>     // Do stuff.
>     }
> catch (ExeptionType value)
>     {
>     object.~Object(value);
>     throw;
>     }
> object.~Object();
> }

As to your proposal, it's not clear to me whether you propose that
destructors be called explicitly. If you don't our proposals are
actually identical except for minor syntactic details. If you do I
consider mine better :-)

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: "Pavel Kuznetsov" <pavel@despammed.com>
Date: Thu, 25 Apr 2002 17:38:23 GMT
Raw View
Nicola Musatti (objectway@divalsim.it) wrote:

NM> (...) allowing destructors
NM> to take one argument. Such destructors would only be called during
NM> stack unwinding and would be passed the active exception.

NM> class Transaction {
NM>   public:
NM>     Transaction() { open(); }
NM>     ~Transaction() { commit(); }
NM>     ~Transaction(std::exception & e) { rollback(); }
NM> };

I like this. I am just curious how to interpret destructors
with several arguments, especially if proposed extention
applies to ellipsis destructors.

--
Pavel

---
[ 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: Alexander Terekhov <terekhov@web.de>
Date: Thu, 25 Apr 2002 19:00:08 GMT
Raw View
xleobx@qmailcomq.com wrote:
>
> Alexander Terekhov <terekhov@web.de> wrote:
>
> >> See 15.5.3 [except.uncaught]
>
> > See: http://groups.google.com/groups?as_umsgid=3CBC5F22.76708D0%40web.de

[..."Okay... ENOUGH active exceptions! ;-)"...]

> Cute, although an  "abuse" of 15.2.3.

Uhmm, why/what "abuse"?

> Is there a request to make std::uncaught_exception() return unsigned int
> instead of bool?

http://groups.google.com/groups?selm=9u8c51%24ij9%241%40news.tuwien.ac.at
( Christopher Eltschka: "Instead returning a bool, return an int telling
_how many_ exceptions are pending.")

I think that it would NOT hurt to have something like that...
but "bool unwinding(obj_ptr)" + "bool expected_ex<ex_t>()" +
"propagating_ex_ptr_or_ref< ex_t >()" + post-/pre- c-/d-tors"
would provide MUCH MORE value/"simplify" a lot of things quite
considerably, I believe. ;-)

regards,
alexander.

---
[ 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: Alexander Terekhov <terekhov@web.de>
Date: Thu, 25 Apr 2002 21:12:40 GMT
Raw View
Alexander Terekhov wrote:
>
> xleobx@qmailcomq.com wrote:
> >
> > Alexander Terekhov <terekhov@web.de> wrote:
> >
> > >> See 15.5.3 [except.uncaught]
> >
> > > See: http://groups.google.com/groups?as_umsgid=3CBC5F22.76708D0%40web.de
>
> [..."Okay... ENOUGH active exceptions! ;-)"...]
>
> > Cute, although an  "abuse" of 15.2.3.
>
> Uhmm, why/what "abuse"?
>
> > Is there a request to make std::uncaught_exception() return unsigned int
> > instead of bool?
>
> http://groups.google.com/groups?selm=9u8c51%24ij9%241%40news.tuwien.ac.at
> ( Christopher Eltschka: "Instead returning a bool, return an int telling
> _how many_ exceptions are pending.")
>
> I think that it would NOT hurt to have something like that...
> but "bool unwinding(obj_ptr)" + "bool expected_ex<ex_t>()" +
> "propagating_ex_ptr_or_ref< ex_t >()" + post-/pre- c-/d-tors"
> would provide MUCH MORE value/"simplify" a lot of things quite
> considerably, I believe. ;-)

Heck! Why not: (my "8 o'clock"-wish list; just ideas ;-))

1. size_t "unwinding(obj_ptr)" (template/macro) -> 0/scope;

2. size_t uncaught_exception_scope() -> 0/scope;

3. "uncaught_ex_ptr_or_ref<T>(size_t scope = 0)" (ref.version throws)
   ("scope = 0" means "current"; in effect: uncaught_exception_scope());

4. "bool expected_exception<T>()";

5. "post-/pre- c-/d-tors";

6. "local context" templates:
http://groups.google.com/groups?selm=3CC4733A.822D7A07%40web.de

7. fix unneeded/harmful "unwinding" problems
   (Ex.specs/"implementation-defined",etc.);

8. deprecate uncaught_exception().

Any objections or am I missing something, folks? ;-) ;-)

regards,
alexander.

---
[ 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: xleobx@qmailcomq.com
Date: Fri, 26 Apr 2002 18:31:54 GMT
Raw View
Alexander Terekhov <terekhov@web.de> wrote:

>> > > See: http://groups.google.com/groups?as_umsgid=3CBC5F22.76708D0%40web.de
>>
>> [..."Okay... ENOUGH active exceptions! ;-)"...]
>>
>> > Cute, although an  "abuse" of 15.2.3.
>>
>> Uhmm, why/what "abuse"?

Because for me it looks like the standard does not "realize" the possibility
of nested exceptions: first, because there is no mention of possibility
of nested stack unwinding, even in a Note; and second,
because uncaught_exception() does return bool and not unsigned.
I quoted the word "abuse", because the standard does not go as
far as directing all exceptions during stack unwinding to terminate()
outright, so your example is not the abuse of its letter, just of its spirit.

>> I think that it would NOT hurt to have something like that...
>> but "bool unwinding(obj_ptr)" + "bool expected_ex<ex_t>()" +
>> "propagating_ex_ptr_or_ref< ex_t >()" + post-/pre- c-/d-tors"
>> would provide MUCH MORE value/"simplify" a lot of things quite
>> considerably, I believe. ;-)

> Heck! Why not: (my "8 o'clock"-wish list; just ideas ;-))

> 1. size_t "unwinding(obj_ptr)" (template/macro) -> 0/scope;

Where should the unwinding scope count stop? At the first non-unwinding
dtor, or not?

> 2. size_t uncaught_exception_scope() -> 0/scope;

> 3. "uncaught_ex_ptr_or_ref<T>(size_t scope = 0)" (ref.version throws)
>    ("scope = 0" means "current"; in effect: uncaught_exception_scope());

What is the return type of it?

> 4. "bool expected_exception<T>()";

How do you check the current exception, the type of which you do not know
statically, against it?

> 5. "post-/pre- c-/d-tors";

Wouldn't an additional level of object wrapping give you the same?

> 6. "local context" templates:
> http://groups.google.com/groups?selm=3CC4733A.822D7A07%40web.de

This is probably too much work implementation-wise.

> 7. fix unneeded/harmful "unwinding" problems
>    (Ex.specs/"implementation-defined",etc.);

> 8. deprecate uncaught_exception().

> Any objections or am I missing something, folks? ;-) ;-)

I believe that functions with a typeid/type_info argument
would be better than templated functions (or a good addition to them);
I want typeid(thrown_object) in catch(...).

 Leo

---
[ 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: Alexander Terekhov <terekhov@web.de>
Date: Fri, 26 Apr 2002 18:32:24 GMT
Raw View
xleobx@qmailcomq.com wrote:
[...]
>         Leo
> missing typeid(exception) in catch(...).

Perhaps this could help:

  void oper(); // could throw anything... incl. "SIGSEGV"-like stuff!

  void checked_oper() throw(A,B,C) // etc. -- all EXPECTED/GOOD ones
  { oper(); }

  /**/
  try {

    checked_oper();

  }
  catch( ... ) {

    handleKnownExpectedExceptions( /**/ );

  }
  /**/

  void handleKnownExpectedExceptions( /**/ )
  {
    try { throw; }
    catch( const A& a ) { /**/ }
    catch( const B& b ) { /**/ }
    catch( const C& c ) { /**/ }
    catch( ... ) { /* all others (if any) */ }
  }

Or do you mean something (as it seems to me)
LESS weird and MORE "generic" from future_std
namespace: ;-)

(missing items from my new "10 o'clock"-wish list; just ideas ;-))

 9. size_t caught_exception_scope() -> 0/scope;
    ("throw;" -- re-throw is OK "if (caught_exception_scope())")

10. "caught_ex_ptr_or_ref<T>(size_t scope = 0)" (ref.version throws)
   ("scope = 0" means "current"; in effect: caught_exception_scope());

Any comments (other than "Huh? Why do you need this?" -- I
don't really know it myself currently; perhaps "just for"
symmetry w.r.t. uncaught_blah_blah stuff), folks? ;-) ;-)

regards,
alexander.

---
[ 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: brangdon@cix.co.uk (Dave Harris)
Date: Fri, 26 Apr 2002 19:36:06 GMT
Raw View
terekhov@web.de (Alexander Terekhov) wrote (abridged):
> How about ( another 0.01 of "serious proposal" ;-)):
> [post-destructor]

That would probably satisfy the efficiency concern. However,
post-destructors are a new feature which make the language more
complicated and harder to understand.

I see allowing destructors to take arguments as making the language more
uniform. Every other kind of function can take arguments; destructors are
currently a special case. It is an arbitrary and unnecessary limitation.
To me, getting rid of that limitation makes the language simpler and
easier to teach.

That it has practical uses is a bonus :-)

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ 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: brangdon@cix.co.uk (Dave Harris)
Date: Sun, 28 Apr 2002 00:16:31 GMT
Raw View
xleobx@qmailcomq.com () wrote (abridged):
> > Perhaps you are thinking that this could be done through an instance
> > variable. That would work, but would add a memory cost to every
> > instance of the class.
>
> Not necessarily. static std::set<Base*> Base::UnregisterSet would do,

If I understand you correctly (and your comments are rather enigmatic),
that would merely move the memory overhead to another place, bloat it
further and add some speed overhead too. All to recover some information
which was already known at compile-time.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ 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: Alexander Terekhov <terekhov@web.de>
Date: Sun, 28 Apr 2002 00:17:18 GMT
Raw View
xleobx@qmailcomq.com wrote:
[...]
> > 1. size_t "unwinding(obj_ptr)" (template/macro) -> 0/scope;
>
> Where should the unwinding scope count stop? At the first non-unwinding
> dtor, or not?

On corresponding *catch handler* entry, which will actually
create another *caught exception scope* (vs. "uncaught" or
"unwinding" scope).

> > 2. size_t uncaught_exception_scope() -> 0/scope;
>
> > 3. "uncaught_ex_ptr_or_ref<T>(size_t scope = 0)" (ref.version throws)
> >    ("scope = 0" means "current"; in effect: uncaught_exception_scope());
>
> What is the return type of it?

T pointer or reference (not sure about "const" vs. "non-const").

> > 4. "bool expected_exception<T>()";
>
> How do you check the current exception, the type of which you do not know
> statically, against it?
>
> > 5. "post-/pre- c-/d-tors";
>
> Wouldn't an additional level of object wrapping give you the same?

Well, sort-of-yes (using factories/"final" wrappers, etc.) But, IMO
it would MUCH simpler and really convenient for *various* things, to
have a second post-construction and pre-destruction invocation chain
(of post-constructors and pre-destructors) performed automatically
(if post/pre- stuff is defined) by the implementation; including
"proper" exception "handling", BTW (I mean e.g. if post-constructor
throws then the whole object should be "eliminated"/cleaned up via
corresponding (if any) pre-destructor(s) first and "normal"
destruction phase next, etc.).

> > 6. "local context" templates:
> > http://groups.google.com/groups?selm=3CC4733A.822D7A07%40web.de
>
> This is probably too much work implementation-wise.

Maybe. Don't know.

regards,
alexander.

---
[ 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: xleobx@qmailcomq.com
Date: Mon, 29 Apr 2002 11:30:59 GMT
Raw View
Dave Harris <brangdon@cix.co.uk> wrote:
>> > Perhaps you are thinking that this could be done through an instance
>> > variable. That would work, but would add a memory cost to every
>> > instance of the class.
>>
>> Not necessarily. static std::set<Base*> Base::UnregisterSet would do,

> If I understand you correctly (and your comments are rather enigmatic),
> that would merely move the memory overhead to another place, bloat it
> further and add some speed overhead too. All to recover some information

I merely demonstrated that the "per-instance" memory overhead can be avoided.

> which was already known at compile-time.

I agree completely that if dtors are allowed to have arguments,
the implementation will be more efficient. But as the desired functionality
can be _easily_ achieved using existing means, and with different
memory/speed tradeoffs, the pressure to have the feature
in the language is less than for a feature that is more sorely missed.

 Leo

---
[ 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: Michiel.Salters@cmg.nl (Michiel Salters)
Date: Mon, 29 Apr 2002 11:31:25 GMT
Raw View
Alexander Terekhov <terekhov@web.de> wrote in message news:<3CCA9C3B.22623F2A@web.de>...
> xleobx@qmailcomq.com wrote:

[ SNIP ]

> > > 5. "post-/pre- c-/d-tors";
> >
> > Wouldn't an additional level of object wrapping give you the same?
>
> Well, sort-of-yes (using factories/"final" wrappers, etc.) But, IMO
> it would MUCH simpler and really convenient for *various* things, to
> have a second post-construction and pre-destruction invocation chain
> (of post-constructors and pre-destructors) performed automatically
> (if post/pre- stuff is defined) by the implementation; including
> "proper" exception "handling", BTW (I mean e.g. if post-constructor
> throws then the whole object should be "eliminated"/cleaned up via
> corresponding (if any) pre-destructor(s) first and "normal"
> destruction phase next, etc.).

Using a wrapper<T> : public T construct, you can have your cake and
eat it too. wrapper<T>::wrapper is a post-ctor for T::T, and the dtor
works too. In addition, throwing does the logical thing and does NOT
call the wrapper dtor ( because the wrapper ctor didn't finish ), but
it does call T::~T. In addition, wrapper<T> IS-A T, so they can be
used interchangably.

Now, why is this more convenient? Because it works with existing
compilers, doesn't introduce additional special functions, it
can be used to implement post-post-ctors, and you can have multiple
wrappers of a single base class.

This is more than theory; in my current project a number of classes
use a wrapper to start and stop their thread_main. It's easy.

Regards,
--
Michiel Salters

---
[ 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@divalsim.it>
Date: Mon, 29 Apr 2002 11:33:18 GMT
Raw View

xleobx@qmailcomq.com wrote:
>
> Nicola Musatti <objectway@divalsim.it> wrote:
[...]
> >> >     ~Transaction(std::exception & e) { rollback(); }
> >> > };
> >>
> >> See 15.5.3 [except.uncaught]
>
> > I'm aware of this [i.e. std::uncaught_exception()], but I consider the
> > proposal above both more powerful and more elegant. Actually this idea
>
> If the standard requires all thrown objects to derive from std::exception,
> maybe. But I do not believe it ever will.

Sorry, I put std::exception in my example, but I would actually allow
overloading of destructors on any type, so that the best fit according
to overload resolution would be called or the standard destructor if no
other destructor matches.

> > was fired by a comment by Andrei Alexandrescu on c.l.c++.m about how
> > objects and error handling apparently don't mix well.
>
> ....don't mix well in C++ as defined by the current standard, I presume?
> I believe the current situation is a (more or less) reasonable tradeoff
> between flexibility and implementability

I may be wrong, but I believe that compilers already have to generate
code to perform stack unwinding. The only required changes would be to
choose the correct destructor and to pass the current exception as an
argument. I don't believe this to pose any problem of implementability.

> like std::uncaught_exception() returning bool instead of something
> more useful, like
> a) type_info of the object being thrown,
> so that the destructor may choose to compare it to relevant typeids and
> retrieve the object being thrown type-safely using some other
> (templated, as Alexander Terekhov proposed) function

A rather clumsy and error prone mechanism, if you ask me.

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: Nicola Musatti <objectway@divalsim.it>
Date: Mon, 29 Apr 2002 11:44:12 GMT
Raw View

Sean Parent wrote:
[...]
> I would like to extend the original proposal to the following:
>
> class Transaction
> {
>  public:
>     ~Transaction() { commit(); }
>     catch ~Transaction(std::exception &e) { rollback(); }
>     catch ~Transaction(...) { rollback(); }
> };

Unless you are proposing an alternative behaviour for something like

~Transaction(std::exception &e) { rollback(); }

the "catch" keyword is not necessary.

> Within a catch destructor the exception is considered "caught". Returning
> from the destructor will call throw to re-throw the current exception. The
> exception can also be rethrown (using throw) from within the destructor, or
> a new exception can be thrown.

My attitude is more conservative: I don't believe that the semantics of
stack unwinding should be modified except for the fact that the
destructor becomes capable of accessing the exception object which
caused its execution.

By the way, I see how the ellipsis version could be useful, but I don't
think I would allow it. First, because it would overload the ellipsis
with a new meaning in the context of function call arguments, which I
don't think is a good thing. Second, because I feel that programmers
using this mechanism should at least make sure they know what they're
throwing.

> Which destructor to invoke is determined in
> the same way which catch clause to execute is. First match wins.

I think I'd use the rules for overload resolution instead, so as not to
make destructors too different from other functions.

> The case I would like to use this for is to "decorate" exception objects
> with context information about what is currently happening.

Exactly.

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: Nicola Musatti <objectway@divalsim.it>
Date: Mon, 29 Apr 2002 11:44:21 GMT
Raw View

Alexander Terekhov wrote:
[...]
> Any objections or am I missing something, folks? ;-) ;-)

I disagree in principle with your proposals. Requiring a very extensive
API to interact with exception handling / stack unwinding is in my
opinion missing the point. The things you describe could be achieved
much more easily by completely forsaking exceptions and returning class
instances from functions instead.

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: Alexander Terekhov <terekhov@web.de>
Date: Mon, 29 Apr 2002 16:57:49 GMT
Raw View
Dave Harris wrote:
>
> terekhov@web.de (Alexander Terekhov) wrote (abridged):
> > How about ( another 0.01 of "serious proposal" ;-)):
> > [post-destructor]
>
> That would probably satisfy the efficiency concern. However,
> post-destructors

Nah, *pre-destructor* (and *post-constructor*).

> are a new feature which make the language more
> complicated and harder to understand.

Absolutely *NOT TRUE*, I believe. On the contrary,
the *current* way of just "lying" w.r.t. polymorphic
behavior (vf/ti/dc) of objects under construction
and destruction is "complicated and harder to
understand" and REALLY ERROR-PRONE, to begin with,
IMHO. If anything, post-/pre stuff would partly address
THAT "problem" (and make many other things "simple",
easy to maintain, etc.[1]), I believe strongly.

regards,
alexander.

[1] For example:

    http://www.cs.umd.edu/~pugh/java/memoryModel/archive/1038.html
    http://www.cs.umd.edu/~pugh/java/memoryModel/archive/1040.html
    (see "or, even better: g) ....."

---
[ 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@divalsim.it>
Date: Mon, 22 Apr 2002 19:32:31 GMT
Raw View
Hallo, everybody.
I hope this hasn't been already discussed to much. In his presentation
on error handling at the ACCU conference Andrei Alexandrescu showed an
example where it was important to know in a class destructor wheter
destruction was taking place due to normal end of scope or to stack
unwinding.

I just thought that this might be achieved by allowing destructors to
take one argument. Such destructors would only be called during stack
unwinding and would be passed the active exception.

This would allow an even more through exploitment of RAII, by providing
a mechanism to obtain automatic commit or rollback according to whether
an exception was thrown. Something like:

class Transaction {
  public:
    Transaction() { open(); }
    ~Transaction() { commit(); }
    ~Transaction(std::exception & e) { rollback(); }
};

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: Alexander Terekhov <terekhov@web.de>
Date: Mon, 22 Apr 2002 21:02:00 GMT
Raw View
Nicola Musatti wrote:
>
> Hallo, everybody.
> I hope this hasn't been already discussed to much. In his presentation
> on error handling at the ACCU conference Andrei Alexandrescu showed an
> example where it was important to know in a class destructor wheter
> destruction was taking place due to normal end of scope or to stack
> unwinding.
>
> I just thought that this might be achieved by allowing destructors to
> take one argument. Such destructors would only be called during stack
> unwinding and would be passed the active exception.
>
> This would allow an even more through exploitment of RAII, by providing
> a mechanism to obtain automatic commit or rollback according to whether
> an exception was thrown. Something like:
>
> class Transaction {
>   public:
>     Transaction() { open(); }
>     ~Transaction() { commit(); }
>     ~Transaction(std::exception & e) { rollback(); }
> };

How about ( 0.01 x "serious proposal" ;-)):

Transaction::~Transaction()
{

  // Unwinding on exception propagation?
  if ( std::unwinding( this ) ) {

    // A) invoke rollback()/whatever

    // B) have access to propagating exception:

    const std::exception* e; // or "whatever" ptr

    if ( 0 != (e = std::propagating_exception_ptr< BadThing >()) ) {

      // Whatever

    }
    else if ( 0 != (e = std::propagating_exception_ptr< AnotherBadThing
>())

      // Whatever

    }

    // Whatever

  }
  else { // "Normal" destruction

    // A) invoke commit()/whatever

    // B) Can't we really throw here?

    if ( some_error ) {

      // Search-for-handler/check Ex.Specs (if any)
      // in the dynamic context
      if ( std::expected_exception< BadThing >() )
        throw BadThing( whatever );

      // Whatever

    }

    // Whatever

  }

}

Also:

http://groups.google.com/groups?as_umsgid=3C73AB86.99B8CBE0%40web.de

"....
 [1] In addition to those two "future_std"
     fancy functions I've mentioned before,
     I think that something along the lines
     of: (just ideas/food for thought)

     future_std_local_context_template< int >
     struct T;

     future_std_local_context_template<>
     struct T< 1 > {  T() { context.blabla...; }
                     ~T() { context.blabla...; }
     };

     future_std_local_context_template<>
     struct T< 2 > { T() { context.blabla...; }
                    ~T() { context.blabla...; }
     };

     void f()
     {
       blabla...;
       future_std_local_context T< 1 > t1;
       ...
       future_std_local_context T< 2 > t2;
     }

     might be rather handy too! ;-)"

http://groups.google.com/groups?as_umsgid=3CC1ABD8.971E71BF%40web.de

"....
 Well, I mean basically something along the lines of:
 (but with a constructor too ;-))


http://groups.google.com/groups?as_umsgid=3A9E5923.29E877B7%40dresdner-bank.com
 (see "- Create a local instance with a destructor: ....")
 ...."

regards,
alexander.

---
[ 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: brangdon@cix.co.uk (Dave Harris)
Date: Tue, 23 Apr 2002 21:09:47 GMT
Raw View
objectway@divalsim.it (Nicola Musatti) wrote (abridged):
> I just thought that this might be achieved by allowing destructors to
> take one argument. Such destructors would only be called during stack
> unwinding and would be passed the active exception.

I have made a more general request for destructor arguments, as a
communication channel for derived classes and placement destruction. I
don't think anyone was very interested though.

Eg:
    class Base {
    public:
        Base( bool shouldRegister=true ) {
            if (!shouldRegister)
                Singleton::instance().add( this );
        }
        ~Base( bool shouldUnregister=true ) {
            if (shouldUnregister)
                Singleton::instance().remove( this );
        }
    };

    class Derived: public Base {
    public:
        Derived() : Base(false) {
            MySingleton::instance().add(this);
        }
        ~Derived() : Base(false) {
            MySingleton::instance().remove(this);
        }
    }

The idea here is that the Base class constructor registers itself by
default, but Derived classes can tell it not to if they have already made
their own arrangements. There is no good way to write this in C++ today,
because there is no good way for a derived destructor to communicate with
its Base one.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ 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: xleobx@qmailcomq.com
Date: Wed, 24 Apr 2002 00:07:28 GMT
Raw View
Dave Harris <brangdon@cix.co.uk> wrote:

> The idea here is that the Base class constructor registers itself by
> default, but Derived classes can tell it not to if they have already made
> their own arrangements. There is no good way to write this in C++ today,
> because there is no good way for a derived destructor to communicate with
> its Base one.

Why isn't calling Base::someMethod() in Derived::~Derived() a good way
to communicate? In ~Derived(), the Base class is still alive and well.

 Leo

---
[ 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: xleobx@qmailcomq.com
Date: Wed, 24 Apr 2002 00:46:01 GMT
Raw View
Nicola Musatti <objectway@divalsim.it> wrote:

> This would allow an even more through exploitment of RAII, by providing
> a mechanism to obtain automatic commit or rollback according to whether
> an exception was thrown. Something like:

> class Transaction {
>   public:
>     Transaction() { open(); }
>     ~Transaction() { commit(); }
>     ~Transaction(std::exception & e) { rollback(); }
> };

See 15.5.3 [except.uncaught]

 Leo

---
[ 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: Alexander Terekhov <terekhov@web.de>
Date: Wed, 24 Apr 2002 00:45:55 GMT
Raw View
Dave Harris wrote:
>
> objectway@divalsim.it (Nicola Musatti) wrote (abridged):
> > I just thought that this might be achieved by allowing destructors to
> > take one argument. Such destructors would only be called during stack
> > unwinding and would be passed the active exception.
>
> I have made a more general request for destructor arguments, as a
> communication channel for derived classes and placement destruction. I
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> don't think anyone was very interested though.
>
> Eg:
>     class Base {
>     public:
>         Base( bool shouldRegister=true ) {
>             if (!shouldRegister)
>                 Singleton::instance().add( this );
>         }
>         ~Base( bool shouldUnregister=true ) {
>             if (shouldUnregister)
>                 Singleton::instance().remove( this );
>         }
>     };
>
>     class Derived: public Base {
>     public:
>         Derived() : Base(false) {
>             MySingleton::instance().add(this);
>         }
>         ~Derived() : Base(false) {
>             MySingleton::instance().remove(this);
>         }
>     }

How about ( another 0.01 of "serious proposal" ;-)):

    class Base {

        // Just an example; m_blahblah would work as well,
        // if needed. Even *pure-virtuals* would WORK!!!!
        virtual bool shouldRegister() { return true; }
        virtual bool shouldUnRegister() { return true; }

        // future_std stuff
        post Base() // post-constructor
        {
          // object is *fully constructed* here
          // POLYMORPHIC BEHAVIOR *WORKS*!!!!

          if ( shouldRegister() )
           MySingleton::instance().add(this);

          // whatever

        }

        // future_std stuff
        pre ~Base() // pre-destructor
        {
          // object is *fully constructed* here
          // POLYMORPHIC BEHAVIOR *WORKS*!!!!

          if ( shouldUnRegister() )
            MySingleton::instance().remove(this);

          // whatever

        }

    public:

        // conventional stuff
        Base( /* whatever */ )
            /* : whatever */  { /* whatever */ }

        /* virtual */ ~Base() { /* whatever */ }

    };

regards,
alexander.

---
[ 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: Alexander Terekhov <terekhov@web.de>
Date: Wed, 24 Apr 2002 16:06:09 GMT
Raw View
xleobx@qmailcomq.com wrote:
>
> Nicola Musatti <objectway@divalsim.it> wrote:
>
> > This would allow an even more through exploitment of RAII, by providing
> > a mechanism to obtain automatic commit or rollback according to whether
> > an exception was thrown. Something like:

[...don't_like_it_sorry...]

> See 15.5.3 [except.uncaught]

See: http://groups.google.com/groups?as_umsgid=3CBC5F22.76708D0%40web.de

"....
 lnxmuell:/usr/terekhov # ./e
 throw 0
 throw 1
 throw 2
 throw 3
 throw 4
 throw 5
 throw 6
 throw 7
 throw 8
 throw 9
 Okay... ENOUGH active exceptions! ;-)
 caught 9
 caught 8
 caught 7
 caught 6
 caught 5
 caught 4
 caught 3
 caught 2
 caught 1
 caught 0
 lnxmuell:/usr/terekhov # cat e.cpp
 ...."

regards,
alexander.

---
[ 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@divalsim.it>
Date: Wed, 24 Apr 2002 16:07:35 GMT
Raw View

xleobx@qmailcomq.com wrote:
>
> Nicola Musatti <objectway@divalsim.it> wrote:
>
> > This would allow an even more through exploitment of RAII, by providing
> > a mechanism to obtain automatic commit or rollback according to whether
> > an exception was thrown. Something like:
>
> > class Transaction {
> >   public:
> >     Transaction() { open(); }
> >     ~Transaction() { commit(); }
> >     ~Transaction(std::exception & e) { rollback(); }
> > };
>
> See 15.5.3 [except.uncaught]

I'm aware of this [i.e. std::uncaught_exception()], but I consider the
proposal above both more powerful and more elegant. Actually this idea
was fired by a comment by Andrei Alexandrescu on c.l.c++.m about how
objects and error handling apparently don't mix well.

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: Nicola Musatti <objectway@divalsim.it>
Date: Wed, 24 Apr 2002 16:07:25 GMT
Raw View

Alexander Terekhov wrote:
>
> Nicola Musatti wrote:
[...]
> > class Transaction {
> >   public:
> >     Transaction() { open(); }
> >     ~Transaction() { commit(); }
> >     ~Transaction(std::exception & e) { rollback(); }
> > };
>
> How about ( 0.01 x "serious proposal" ;-)):
>
> Transaction::~Transaction()
> {
>   if ( std::unwinding( this ) ) {
>     rollback();
>     const std::exception* e; // or "whatever" ptr
>     if ( 0 != (e = std::propagating_exception_ptr< BadThing >()) ) {
>       // Whatever
>     }
>     else if ( 0 != (e = std::propagating_exception_ptr<
>                     AnotherBadThing >()))
>       // Whatever
>     }
>     // Whatever
>   }
>   else {
>     commit();
>     if ( some_error ) {
>       // Search-for-handler/check Ex.Specs (if any)
>       // in the dynamic context
>       if ( std::expected_exception< BadThing >() )
>         throw BadThing( whatever );
>     }
>   }
> }

I slightly modified your example so that the two can be compared. In my
opinion the unwinding branch in your example can be more cleanly
implemented as a set of destructors overloaded on exception type.

On the other hand I'm aware that my proposal violates Bjarne
Stroustrup's suggestion that core language changes be kept to a minimum;
a point of view which I share by the way.

I'm not sure I understood correctly what your std::expected_exception()
is expected to do, so I'll withold my negative comments until I know
better :-)

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: brangdon@cix.co.uk (Dave Harris)
Date: Wed, 24 Apr 2002 19:25:25 GMT
Raw View
xleobx@qmailcomq.com () wrote (abridged):
> Why isn't calling Base::someMethod() in Derived::~Derived() a good way
> to communicate?

Well, then Base::someMethod() needs to communicate with Base::~Base(),
because that is where the unregistering happens.

Perhaps you are thinking that this could be done through an instance
variable. That would work, but would add a memory cost to every instance
of the class.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ 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: xleobx@qmailcomq.com
Date: Wed, 24 Apr 2002 20:39:52 GMT
Raw View
Alexander Terekhov <terekhov@web.de> wrote:

>> See 15.5.3 [except.uncaught]

> See: http://groups.google.com/groups?as_umsgid=3CBC5F22.76708D0%40web.de

> "....
>  lnxmuell:/usr/terekhov # ./e
>  throw 0
>  throw 1
>  throw 2
>  throw 3
>  throw 4
>  throw 5
>  throw 6
>  throw 7
>  throw 8
>  throw 9
>  Okay... ENOUGH active exceptions! ;-)
>  caught 9
>  caught 8
>  caught 7
>  caught 6
>  caught 5
>  caught 4
>  caught 3
>  caught 2
>  caught 1
>  caught 0
>  lnxmuell:/usr/terekhov # cat e.cpp
>  ...."


Cute, although an  "abuse" of 15.2.3.
Is there a request to make std::uncaught_exception() return unsigned int
instead of bool?

 Leo

---
[ 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: xleobx@qmailcomq.com
Date: Wed, 24 Apr 2002 20:46:23 GMT
Raw View
Dave Harris <brangdon@cix.co.uk> wrote:
> xleobx@qmailcomq.com () wrote (abridged):
>> Why isn't calling Base::someMethod() in Derived::~Derived() a good way
>> to communicate?

> Well, then Base::someMethod() needs to communicate with Base::~Base(),
> because that is where the unregistering happens.

> Perhaps you are thinking that this could be done through an instance
> variable. That would work, but would add a memory cost to every instance
> of the class.

Not necessarily. static std::set<Base*> Base::UnregisterSet would do,

 Leo

---
[ 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: xleobx@qmailcomq.com
Date: Wed, 24 Apr 2002 20:53:55 GMT
Raw View
Nicola Musatti <objectway@divalsim.it> wrote:


> xleobx@qmailcomq.com wrote:
>>
>> Nicola Musatti <objectway@divalsim.it> wrote:
>>
>> > This would allow an even more through exploitment of RAII, by providing
>> > a mechanism to obtain automatic commit or rollback according to whether
>> > an exception was thrown. Something like:
>>
>> > class Transaction {
>> >   public:
>> >     Transaction() { open(); }
>> >     ~Transaction() { commit(); }
>> >     ~Transaction(std::exception & e) { rollback(); }
>> > };
>>
>> See 15.5.3 [except.uncaught]

> I'm aware of this [i.e. std::uncaught_exception()], but I consider the
> proposal above both more powerful and more elegant. Actually this idea

If the standard requires all thrown objects to derive from std::exception,
maybe. But I do not believe it ever will.

> was fired by a comment by Andrei Alexandrescu on c.l.c++.m about how
> objects and error handling apparently don't mix well.

....don't mix well in C++ as defined by the current standard, I presume?
I believe the current situation is a (more or less) reasonable tradeoff
between flexibility and implementability, modulo some small mistakes,
like std::uncaught_exception() returning bool instead of something
more useful, like
a) type_info of the object being thrown,
so that the destructor may choose to compare it to relevant typeids and
retrieve the object being thrown type-safely using some other
(templated, as Alexander Terekhov proposed) function, and/or

b) exception nesting level (I'd like to see that trick being used in
real life, though). Otherwise, if someone wants full visibility
of the call stack, exception stack, etc., as they say,
"If you want Forth, you know where to find it." :-)

 Leo
missing typeid(exception) in catch(...).

---
[ 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: Alexander Terekhov <terekhov@web.de>
Date: Thu, 25 Apr 2002 16:59:42 GMT
Raw View
Nicola Musatti wrote:
[...]
> I slightly modified your example so that the two can be compared. In my
> opinion the unwinding branch in your example can be more cleanly
> implemented as a set of destructors overloaded on exception type.

What do you mean with "more cleanly implemented" and why
"a set of destructors overloaded on exception type" is
better than a single destructor (and/or pre-destructor)
capable (optionally) of "branching" on:

A) *any* object (including "this") being "unwound" or not;

B) type and info of the exception being propagated,
   even if "this" object itself IS NOT "unwound";
   this would work even in a constructor (and/or
   post-constructor) if that info is needed for
   some reason there.

BTW, check out this proposal/idea too:

http://groups.google.com/groups?as_umsgid=3BC7214E.CDD9CF8E%40iobox.com
(Sergey P. Derevyago: "~A(bool in_stack_unwinding)")

I don't like it either. ;-)

> On the other hand I'm aware that my proposal violates Bjarne
> Stroustrup's suggestion that core language changes be kept to a minimum;
> a point of view which I share by the way.

Yep.

> I'm not sure I understood correctly what your std::expected_exception()
> is expected to do, so I'll withold my negative comments until I know
> better :-)

See: http://www.codesourcery.com/cxx-abi/abi-eh.html

std::expected_exception() is meant to perform search/check
for Ex.Spec violation and collision with already active
exception. Basically, if it returns false (for a given type)
then throwing it as exception is guaranteed to end up in
unexpected() or terminate() altogether. More on this,
including archaic "setjmp"-based exception impls without
"search phase only":

http://groups.google.com/groups?as_umsgid=3C91397A.9FC5F5A4%40web.de
(see "OK, you probably mean something along the lines of: ....",
and please don't miss "P.S." section ;-))

regards,
alexander.

---
[ 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: Sean Parent <sparent@adobe.com>
Date: Thu, 25 Apr 2002 17:38:21 GMT
Raw View
There are two problems with uncaught_exception().

The first, is that it doesn't supply information about whether a particular
object is being destructed because of an unwind or just because it fell out
of scope. This is because several exceptions may be in flight or because the
object is declared inside a destructor that is being unwound.

The second problem is that it doesn't give any way to recover the exception,
or to modify it. I would like to extend the original proposal to the
following:

class Transaction
{
 public:
    ~Transaction() { commit(); }
    catch ~Transaction(std::exception &e) { rollback(); }
    catch ~Transaction(...) { rollback(); }
};

Within a catch destructor the exception is considered "caught". Returning
from the destructor will call throw to re-throw the current exception. The
exception can also be rethrown (using throw) from within the destructor, or
a new exception can be thrown. Which destructor to invoke is determined in
the same way which catch clause to execute is. First match wins.

The case I would like to use this for is to "decorate" exception objects
with context information about what is currently happening. Although this
can be done with try / catch clauses, doing so is more cumbersome than using
objects. For example, compare the following code:

void Do_Foo()
{
    doing_t doing("Doing Foo");
    // ... Do stuff
}

VS.

void Do_Foo()
{
    doing_t doing("Doing Foo");
    try
    {
        // ... Do stuff
    }
    catch (...)
    {
        doing.decorate_exception(); // will re-throw
    }
}

Now consider how much more complex this can get if Foo already has some
catch clauses. I either have to carefully consider where to call
decorate_exception() or I have to nest my try blocks.

Sean


in article qDmx8.7104$T_.156237@iad-read.news.verio.net,
xleobx@qmailcomq.com at xleobx@qmailcomq.com wrote on 4/23/02 5:46 PM:

> Nicola Musatti <objectway@divalsim.it> wrote:
>
>> This would allow an even more through exploitment of RAII, by providing
>> a mechanism to obtain automatic commit or rollback according to whether
>> an exception was thrown. Something like:
>
>> class Transaction {
>>   public:
>>     Transaction() { open(); }
>>     ~Transaction() { commit(); }
>>     ~Transaction(std::exception & e) { rollback(); }
>> };
>
> See 15.5.3 [except.uncaught]
>
> Leo
>
> ---
> [ 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                       ]
>

---
[ 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                       ]