This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [rfc] fix libstdc++/10606


>> It all depends on what you consider uncaught_exception useful
>> for, I guess.
>
>When uncaught_exception() returns true, throwing an exception may
>(but isn't required to) cause the runtime to call terminate().
>When it returns false, throwing an exception is guaranteed not
>to cause a call to terminate (provided there's a handler for it,
>of course). This is useful in implementing the copy ctors of
>exception classes.

Also exceptions in dtors... there is standard-mandated usage for this already.

> From the table in core issue 475, requiring "0|1|1|1" as the
>proposed resolution suggests, means that either of "0|1|1|1|OK"
>and "0|1|1|1|ABRT" is permitted. Requiring "0|0|1|1" (which would
>be my preference) would mean that only "0|0|1|1|OK" would be
>allowed (i.e., no call to terminate() could happen during the
>construction of the [temporary] object to be thrown).

For the lazy among us, can you post the test code for constructing
that table please?

>Suppose "0|1|1|1" is required and you are implementing the copy
>ctor of an exception class. You'd have to code it along these
>lines for exception safety:
>
>   struct B { /* third party non-exception class */ };
>   struct M { /* third party non-exception class */ };
>
>   struct S: B {
>       M m;
>       S (const S &rhs)
>           try: B (rhs), m (rhs.m) { /* ... */ }
>           catch (...) {
>               if (std::uncaught_exception ()) {
>                   // what to do here?
>               }
>               else
>                   throw;
>           }
>   };
>
>   try {
>       throw S ();   // can only throw S or call terminate()
>   }
>   catch (const S &s) { /* cannot throw */ }
>   catch (...) { /* never reached */ }

Disaster....

>If, on the other hand, "0|0|1|1" were required, the copy ctor wouldn't
>have to worry about exceptions and could simply let them propagate to
>the caller. If an exception occurred while S was being thrown the new
>exception would simply displace S. A defensively written program won't
>catch exceptions by value so S won't have to worry about terminate()
>being called while the handler's exception object is being initialized.
>The code would look like this:
>
>   struct S: B {
>       M m;
>       S (const S &rhs): B (rhs), m (rhs.m) { /* ... */ }
>   };
>
>   try {
>       throw S ();   // can throw S or anything else
>   }
>   catch (const S &s) { /* cannot throw */ }
>   catch (...) { /* handle exceptions thrown from S::S(const S&) */ }

...compelling.

Also, this clarifies/simplifies uncaught_exception to something that
means true when an exception object (not temporary object) is "in
flight." I like that part.

-benjamin


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]