Topic: Differentiating destructor invocation contexts


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Mon, 10 Dec 2012 17:32:40 +0100
Raw View
This is a multi-part message in MIME format.
--------------040606000405000900080503
Content-Type: text/plain; charset=ISO-8859-1


Here's a proposal to offer a core feature where std::uncaught_exception() fails.
Also available at http://jmaurer.awardspace.info/wg21/destructor-unwinding.html .

Feedback is welcome.

Jens

--




--------------040606000405000900080503
Content-Type: text/html;
 name="destructor-unwinding.html"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="destructor-unwinding.html"

<html>
<head>
<title>Differentiating destructor invocation contexts</title>

<style type="text/css">
  ins { text-decoration:none; font-weight:bold; background-color:#A0FFA0 }
  del { text-decoration:line-through; background-color:#FFA0A0 }
</style>

</head>

<body>
Jens Maurer<br>
2012-12-10

<h1>Differentiating destructor invocation contexts</h1>

<h2>Motivation</h2>

<p>
Herb Sutter's <a href="http://www.gotw.ca/gotw/047.htm">discussion of
std::uncaught_exception()</a> concludes "Unfortunately, I do not know
of any good and safe use for std::uncaught_exception. My advice: Don't
use it."
</p>

<p>
The technical reason (aside from the moral objection) is the inability
to differentiate between "this destructor was directly called by
stack unwinding" and "stack unwinding is ongoing, but this destructor
was called from a regular scope exit".  However, sometimes exactly
this differentiation would be helpful to perform additional cleanup
specific to stack unwinding only.  Example:
</p>
<pre>
  struct Transaction {
    Transaction();
    ~Transaction() {
      if (std::uncaught_exception())
        RollBack();
      else
        Commit();
    }
  };
</pre>

The well-intended meaning was for a transaction to roll back if its
scope was exited via an exception.  However, this detection is
unreliable for the following usage:

<pre>
  U::~U() {
    try {
      Transaction t( /*...*/ );
      // do work
    } catch( ... ) {
      // clean up
    }
  }
</pre>

If U::~U() is called during stack unwinding, the transaction inside
will always roll back, although "commit" was expected. Note that the
the transaction construct could appear in a called function that is
not (and should not be) aware of the context from which it is called.

<h2>Approach</h2>

The signature of the destructor is changed to allow differentiation
between the two code paths. (General idea by
<a href="https://github.com/panaseleus/stack_unwinding#d-style-scope-guardsactions">Evgeny
Panasyuk</a>.)
The differentiation can be made at
compile time by choosing different overloads of the destructor; there
is no inherent need for runtime differentiation.  This also fits well
with today's implementations of stack unwinding, where a distinct code
path from normal scope exit is used.

<pre>
struct S {
  ~S();    // regular destructor
  ~S(int); // unwinding destructor
};
</pre>

Features:
<ul>
<li>A regular destructor always calls regular base and member
destructors.</li>
<li>An unwinding destructor prefers unwinding destructors for bases
and members, but calls the regular destructor if no unwinding one is
available.</li>
<li>If there is no regular destructor in a class, an implicit one is
declared/defined.</li>
<li>If there is no unwinding destructor in a class and any base or
member has an unwinding destructor, an implicit one is
declared/defined.</li>
<li>Scope exit and delete-expressions call the
regular destructor.</li>
<li>Stack unwinding (including failed construction) calls the
unwinding destructor (if present) with an unspecified value for the
argument.</li>
</ul>

The transaction example could then be written like this:

<pre>
  struct Transaction {
    ~Transaction()
    {
      Commit();
    }

    ~Transaction(int)
    {
      RollBack();
    }
  };
</pre>


<h2>Discussion</h2>

Existing code will continue to work as before; only new code expressly
using the new feature will be affected.  No additional keyword is
consumed.  The "int" parameter for the unwinding destructor is
motivated by a roughly similar use for overloaded increment and
decrement operators; see 13.5.7 over.inc.

<h2>Proposed Wording Changes</h2>

These changes assume that the proposed resolution for core issue 1435
has been applied.

<p>

(TBD)

</body>
</html>

--------------040606000405000900080503--

.


Author: "Vicente J. Botet Escriba" <vicente.botet@wanadoo.fr>
Date: Mon, 10 Dec 2012 18:59:09 +0100
Raw View
This is a multi-part message in MIME format.
--------------060602020208040204000307
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: quoted-printable

Le 10/12/12 17:32, Jens Maurer a =E9crit :
> Here's a proposal to offer a core feature where std::uncaught_exception()=
 fails.
> Also available at http://jmaurer.awardspace.info/wg21/destructor-unwindin=
g.html .
>
>
Hi,

I'm not a compiler writer and I don't know if this is simple to=20
implement, but from the user point of view the semantics seems quite clear.
Let me see if I understood it clearly. In the following example

   U::~U(int) {
     try {
       Transaction t( /*...*/ );
       // do work
     } catch( ... ) {
       // clean up
     }
   }

the destructor of t would call the regular constructor, isn't it?

Been able to define the transaction class should be a must for the=20
future C++ version.

Vicente

--=20




--------------060602020208040204000307
Content-Type: text/html; charset=ISO-8859-1

<html>
  <head>
    <meta content="text/html; charset=ISO-8859-1"
      http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <div class="moz-cite-prefix">Le 10/12/12 17:32, Jens Maurer a
      &eacute;crit&nbsp;:<br>
    </div>
    <blockquote cite="mid:50C60EA8.5010202@gmx.net" type="cite">
      <pre wrap="">
Here's a proposal to offer a core feature where std::uncaught_exception() fails.
Also available at <a class="moz-txt-link-freetext" href="http://jmaurer.awardspace.info/wg21/destructor-unwinding.html">http://jmaurer.awardspace.info/wg21/destructor-unwinding.html</a> .


</pre>
    </blockquote>
    Hi,<br>
    <br>
    I'm not a compiler writer and I don't know if this is simple to
    implement, but from the user point of view the semantics seems quite
    clear.<br>
    Let me see if I understood it clearly. In the following example<br>
    <br>
    <meta http-equiv="content-type" content="text/html;
      charset=ISO-8859-1">
    <pre>  U::~U(int) {
    try {
      Transaction t( /*...*/ );
      // do work
    } catch( ... ) {
      // clean up
    }
  }</pre>
    the destructor of t would call the regular constructor, isn't it?<br>
    <br>
    Been able to define the transaction class should be a must for the
    future C++ version.<br>
    <br>
    Vicente<br>
  </body>
</html>

<p></p>

-- <br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />

--------------060602020208040204000307--

.


Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Mon, 10 Dec 2012 20:21:52 +0200
Raw View
On 10 December 2012 18:32, Jens Maurer <Jens.Maurer@gmx.net> wrote:
> Here's a proposal to offer a core feature where std::uncaught_exception() fails.
> Also available at http://jmaurer.awardspace.info/wg21/destructor-unwinding.html .
> Feedback is welcome.

Can I delegate from one destructor to another?

--




.


Author: Nevin Liber <nevin@eviloverlord.com>
Date: Mon, 10 Dec 2012 12:38:29 -0600
Raw View
--0015175cfccc8a3a4504d083e185
Content-Type: text/plain; charset=ISO-8859-1

On 10 December 2012 12:21, Ville Voutilainen <ville.voutilainen@gmail.com>wrote:

> On 10 December 2012 18:32, Jens Maurer <Jens.Maurer@gmx.net> wrote:
> > Here's a proposal to offer a core feature where
> std::uncaught_exception() fails.
> > Also available at
> http://jmaurer.awardspace.info/wg21/destructor-unwinding.html .
> > Feedback is welcome.
>
> Can I delegate from one destructor to another?
>

By delegate do you mean delegating all work, or just the "body" of the
destructor, while member variables and base classes are destroyed via their
own ~T(int) destructors.

I'd like to see an explanation of how this is intended to interact (both
user and typical implementation impact) with access specifiers and
virtualness.
--
 Nevin ":-)" Liber  <mailto:nevin@eviloverlord.com>  (847) 691-1404

--




--0015175cfccc8a3a4504d083e185
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

On 10 December 2012 12:21, Ville Voutilainen <span dir=3D"ltr">&lt;<a href=
=3D"mailto:ville.voutilainen@gmail.com" target=3D"_blank">ville.voutilainen=
@gmail.com</a>&gt;</span> wrote:<br><div class=3D"gmail_quote"><blockquote =
class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid=
;padding-left:1ex">

<div class=3D"HOEnZb"><div class=3D"h5">On 10 December 2012 18:32, Jens Mau=
rer &lt;<a href=3D"mailto:Jens.Maurer@gmx.net">Jens.Maurer@gmx.net</a>&gt; =
wrote:<br>
&gt; Here&#39;s a proposal to offer a core feature where std::uncaught_exce=
ption() fails.<br>
&gt; Also available at <a href=3D"http://jmaurer.awardspace.info/wg21/destr=
uctor-unwinding.html" target=3D"_blank">http://jmaurer.awardspace.info/wg21=
/destructor-unwinding.html</a> .<br>
&gt; Feedback is welcome.<br>
<br>
</div></div>Can I delegate from one destructor to another?<br></blockquote>=
<div><br></div><div>By delegate do you mean delegating all work, or just th=
e &quot;body&quot; of the destructor, while member variables and base class=
es are destroyed via their own ~T(int) destructors.</div>

<div><br></div><div>I&#39;d like to see an explanation of how this is inten=
ded to interact (both user and typical implementation impact) with access s=
pecifiers and virtualness.</div></div>-- <br>=A0Nevin &quot;:-)&quot; Liber=
=A0 &lt;mailto:<a href=3D"mailto:nevin@eviloverlord.com" target=3D"_blank">=
nevin@eviloverlord.com</a>&gt;=A0 (847) 691-1404<br>


<p></p>

-- <br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />

--0015175cfccc8a3a4504d083e185--

.


Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Mon, 10 Dec 2012 20:46:59 +0200
Raw View
On 10 December 2012 20:38, Nevin Liber <nevin@eviloverlord.com> wrote:
>> Can I delegate from one destructor to another?
> By delegate do you mean delegating all work, or just the "body" of the
> destructor, while member variables and base classes are destroyed via their
> own ~T(int) destructors.

I think the body. Delegating constructors allow me to get rid of weird
init() functions,
I'd hate to see cleanup() counterpart suddenly coming back because I want to do
things shared between multiple destructors.

> I'd like to see an explanation of how this is intended to interact (both
> user and typical implementation impact) with access specifiers and
> virtualness.

"This" as in the delegation question or the feature as proposed by Jens? :)

--




.


Author: Nevin Liber <nevin@eviloverlord.com>
Date: Mon, 10 Dec 2012 12:47:55 -0600
Raw View
--000e0ce009ba3ee42004d0840311
Content-Type: text/plain; charset=ISO-8859-1

On 10 December 2012 12:46, Ville Voutilainen <ville.voutilainen@gmail.com>wrote:

>
> > I'd like to see an explanation of how this is intended to interact (both
> > user and typical implementation impact) with access specifiers and
> > virtualness.
>
> "This" as in the delegation question or the feature as proposed by Jens? :)
>

The feature.
--
 Nevin ":-)" Liber  <mailto:nevin@eviloverlord.com>  (847) 691-1404

--




--000e0ce009ba3ee42004d0840311
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

On 10 December 2012 12:46, Ville Voutilainen <span dir=3D"ltr">&lt;<a href=
=3D"mailto:ville.voutilainen@gmail.com" target=3D"_blank">ville.voutilainen=
@gmail.com</a>&gt;</span> wrote:<br><div class=3D"gmail_quote"><blockquote =
class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid=
;padding-left:1ex">

<br><div class=3D"im">
&gt; I&#39;d like to see an explanation of how this is intended to interact=
 (both<br>
&gt; user and typical implementation impact) with access specifiers and<br>
&gt; virtualness.<br>
<br>
</div>&quot;This&quot; as in the delegation question or the feature as prop=
osed by Jens? :)<br clear=3D"all"></blockquote><div><br>The feature. <br></=
div></div>-- <br>=A0Nevin &quot;:-)&quot; Liber=A0 &lt;mailto:<a href=3D"ma=
ilto:nevin@eviloverlord.com" target=3D"_blank">nevin@eviloverlord.com</a>&g=
t;=A0 (847) 691-1404<br>


<p></p>

-- <br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />

--000e0ce009ba3ee42004d0840311--

.


Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Mon, 10 Dec 2012 21:06:54 +0200
Raw View
On 10 December 2012 20:47, Nevin Liber <nevin@eviloverlord.com> wrote:
>> > I'd like to see an explanation of how this is intended to interact (both
>> > user and typical implementation impact) with access specifiers and
>> > virtualness.

I suppose the same question applies further for cases where one destructor
is user-provided and the other isn't.

--




.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Mon, 10 Dec 2012 23:30:45 +0100
Raw View
On 12/10/2012 06:59 PM, Vicente J. Botet Escriba wrote:
>   U::~U(int) {
>     try {
>       Transaction t( /*...*/ );
>       // do work
>     } catch( ... ) {
>       // clean up
>     }
>   }
>
> the destructor of t would call the regular constructor, isn't it?

Yes, this would call the regular destructor (not constructor) for t.

Jens

--




.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Mon, 10 Dec 2012 23:33:45 +0100
Raw View
On 12/10/2012 07:21 PM, Ville Voutilainen wrote:
> Can I delegate from one destructor to another?

No.

If you need this, you need to implement a helper function called
from both destructors.

I'm hoping that your class is sufficiently small (similar to the
Transaction class) that there is essentially no overlap.

Jens


--




.


Author: Christof Meerwald <cmeerw@cmeerw.org>
Date: Mon, 10 Dec 2012 23:34:07 +0100
Raw View
On Mon, Dec 10, 2012 at 05:32:40PM +0100, Jens Maurer wrote:
> Here's a proposal to offer a core feature where std::uncaught_exception() fails.
> Also available at http://jmaurer.awardspace.info/wg21/destructor-unwinding.html .
[...]
> If there is no unwinding destructor in a class and any base or
> member has an unwinding destructor, an implicit one is
> declared/defined.

Not sure how common it would be for classes to implement unwinding
destructors, but consider the following example:

struct B
{
  A a;

  ~B()
  {
    do_stuff();
  }
};

void foo()
{
  B b;
  throw 0;
}

If A doesn't implement an unwinding destructur, B's destructor will
call do_stuff, but if A implements an unwinding destructor, ~B(int)
will be implicitly declared/defined and do_stuff won't be called?
Looks a bit surprising to me.


Christof

--

http://cmeerw.org                              sip:cmeerw at cmeerw.org
mailto:cmeerw at cmeerw.org                   xmpp:cmeerw at cmeerw.org

--




.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Mon, 10 Dec 2012 23:44:27 +0100
Raw View
On 12/10/2012 07:38 PM, Nevin Liber wrote:
> I'd like to see an explanation of how this is intended to interact
> (both user and typical implementation impact) with access specifiers
> and virtualness.

Access specifiers work as usual, i.e. you first select the function
you want to call, and then you check access.  The program is ill-formed
if you don't have access to the function (= destructor) you've chosen.

So, a private unwinding destructor for a block-scope variable will
be ill-formed.  (I don't think we want to specify the situations
when no exception can possibly pass through.)

A private unwinding destructor for a subobject will cause any
constructor of the complete object to be ill-formed.

A private unwinding destructor for a complete object would allow
allocation via new and deallocation via delete, but would prohibit
use at block scope.

Virtualness is a bit of a non-issue, because unwinding destructors
are only used for objects at block scope and subobjects that are
both (at that point) essentially non-polymorphic.

So, I think we should outlaw virtual unwinding destructors.

That brings up an interesting topic:  Should there be a way
to explicitly invoke an unwinding destructor via "delete" so
that a unique_ptr<> going out of scope could pass on the
unwinding vs. normal scope exit info to its referent?  That
seems to be a bit overkill to me.

Jens

--




.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Mon, 10 Dec 2012 23:55:45 +0100
Raw View
On 12/10/2012 11:34 PM, Christof Meerwald wrote:
> Not sure how common it would be for classes to implement unwinding
> destructors,

It should be a rare case.  Except for the transaction classes
alluded to earlier, it can be used to emulate the "D" scope(failure)
and scope(success) features.

>   but consider the following example:
>
> struct B
> {
>   A a;
>
>   ~B()
>   {
>     do_stuff();
>   }
> };
>
> void foo()
> {
>   B b;
>   throw 0;
> }
>
> If A doesn't implement an unwinding destructur, B's destructor will
> call do_stuff, but if A implements an unwinding destructor, ~B(int)
> will be implicitly declared/defined and do_stuff won't be called?
> Looks a bit surprising to me.

"A" will be equally surprised if its unwinding destructor doesn't
get called at the right time.

I think deriving from a class that has an unwinding destructor
(or having one as a member) is an even rarer case, so maybe the
above should just be ill-formed unless B has an explicit unwinding
destructor.  (Calling a regular destructor from an unwinding one
is ok, but the other way round is not.)

Jens

--




.


Author: Olaf van der Spek <olafvdspek@gmail.com>
Date: Mon, 10 Dec 2012 15:04:04 -0800 (PST)
Raw View
------=_Part_371_8611409.1355180644359
Content-Type: text/plain; charset=ISO-8859-1

Op maandag 10 december 2012 17:32:40 UTC+1 schreef Jens Maurer het volgende:

>
> Here's a proposal to offer a core feature where std::uncaught_exception()
> fails.
> Also available at
> http://jmaurer.awardspace.info/wg21/destructor-unwinding.html .
>
> Feedback is welcome.
>

It's just about the example, I hope you don't mind:
What about rolling back the transaction unless explicitly commited?
Seems cleaner and safer, no unexpected commits.

--




------=_Part_371_8611409.1355180644359
Content-Type: text/html; charset=ISO-8859-1

Op maandag 10 december 2012 17:32:40 UTC+1 schreef Jens Maurer het volgende:<br><blockquote class="gmail_quote" style="margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<br>Here's a proposal to offer a core feature where std::uncaught_exception() fails.
<br>Also available at <a href="http://jmaurer.awardspace.info/wg21/destructor-unwinding.html" target="_blank">http://jmaurer.awardspace.<wbr>info/wg21/destructor-<wbr>unwinding.html</a> .
<br>
<br>Feedback is welcome.
<br></blockquote><div><br></div><div>It's just about the example, I hope you don't mind:</div><div>What about rolling back the transaction unless explicitly commited?</div><div>Seems cleaner and safer, no unexpected commits.</div>

<p></p>

-- <br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_371_8611409.1355180644359--

.


Author: Jean-Marc Bourguet <jm@bourguet.org>
Date: Tue, 11 Dec 2012 09:58:36 +0100
Raw View
On Mon, 10 Dec 2012 23:55:45 +0100, Jens Maurer <Jens.Maurer@gmx.net>
wrote:
> On 12/10/2012 11:34 PM, Christof Meerwald wrote:
>> Not sure how common it would be for classes to implement unwinding
>> destructors,
>
> It should be a rare case.  Except for the transaction classes
> alluded to earlier, it can be used to emulate the "D" scope(failure)
> and scope(success) features.
>
>>   but consider the following example:
>>
>> struct B
>> {
>>   A a;
>>
>>   ~B()
>>   {
>>     do_stuff();
>>   }
>> };
>>
>> void foo()
>> {
>>   B b;
>>   throw 0;
>> }
>>
>> If A doesn't implement an unwinding destructur, B's destructor will
>> call do_stuff, but if A implements an unwinding destructor, ~B(int)
>> will be implicitly declared/defined and do_stuff won't be called?
>> Looks a bit surprising to me.
>
> "A" will be equally surprised if its unwinding destructor doesn't
> get called at the right time.
>
> I think deriving from a class that has an unwinding destructor
> (or having one as a member) is an even rarer case, so maybe the
> above should just be ill-formed unless B has an explicit unwinding
> destructor.  (Calling a regular destructor from an unwinding one
> is ok, but the other way round is not.)

An error would be fine with me as would generating an unwinding
destructor
sharing the same body as the non-unwinding one but called unwinding
destructors
for member and bases (that reminds me what is done to handle virtual
bases;
I'm not knowledgeable about ABI enough to know if it can be reused or
not).
I'd not be fine with generating an unwinding destructor with an empty
body.
It looks too much like an opportunity for errors. Part of me preferred
the error
until I though about templates.  I fear that having an error will leads
template
writers to routinely provide an unwinding destructor and my guess is
that it will
often do just the same as the non-unwinding one in its body. But that
will spread
the use of unwinding destructors forcing class writer to do the same
thing.  This
could be mitigated by providing a way for template writers to not
provide unwinding
destructors if none is needed (and that would be probably useful even
if there is
an automatically generated unwinding destructor instead of an error).


One probably also need a way to explicitly call the unwinding
destructor for cases
where you separate allocation and lifetime management.

a::~A(1);

is the obvious candidate.

I'm undecided on the related subject of having version of delete
calling the unwinding
destructors, but note that the above facility isn't enough to provide
the functionality
because member operator delete are dynamically dispatched.  So

t = new T;
t->~T(1);
operator delete(t);

won't do what is needed. (And (*t).operator delete(t) isn't a valid
alternative).


Yours,

--
Jean-Marc

--




.


Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Tue, 11 Dec 2012 11:17:58 +0200
Raw View
On 11 December 2012 10:58, Jean-Marc Bourguet <jm@bourguet.org> wrote:
> One probably also need a way to explicitly call the unwinding
> destructor for cases
> where you separate allocation and lifetime management.
> a::~A(1);
> is the obvious candidate.
> I'm undecided on the related subject of having version of delete
> calling the unwinding
> destructors, but note that the above facility isn't enough to provide
> the functionality
> because member operator delete are dynamically dispatched.  So
> t = new T;
> t->~T(1);
> operator delete(t);
> won't do what is needed. (And (*t).operator delete(t) isn't a valid
> alternative).

This gives me serious heartburn. And the indication from that burn is that
perhaps it would be better to provide a support library function through which
destructor authors can decide what they will do in a normal destructor.

--




.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Tue, 11 Dec 2012 11:16:57 +0100
Raw View
On 12/11/2012 10:17 AM, Ville Voutilainen wrote:
>    And the indication from that burn is that
> perhaps it would be better to provide a support library function through which
> destructor authors can decide what they will do in a normal destructor.

So, you'd be more in favor of a std::called_from_unwinding() that actually
does what we want here?  I fear that won't be implementable (easily):
When does the return value of that function change from "true" to "false"?
And back?
Is that a point where the implementation can reasonably inject code to
effect the return value change?

Jens


--




.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Tue, 11 Dec 2012 11:19:34 +0100
Raw View
On 12/11/2012 12:04 AM, Olaf van der Spek wrote:
> It's just about the example, I hope you don't mind:
> What about rolling back the transaction unless explicitly commited?

That's a design choice you can make.  With current C++11, it seems to
be the only reasonable design choice.

> Seems cleaner and safer, no unexpected commits.

Well, that depends on your expectations, I'd guess.  A part of the job
of the C++ language specification is to induce appropriate
expectations :-)

Jens

--




.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Tue, 11 Dec 2012 11:25:29 +0100
Raw View
On 12/11/2012 09:58 AM, Jean-Marc Bourguet wrote:
> On Mon, 10 Dec 2012 23:55:45 +0100, Jens Maurer <Jens.Maurer@gmx.net>
> wrote:
>> I think deriving from a class that has an unwinding destructor
>> (or having one as a member) is an even rarer case, so maybe the
>> above should just be ill-formed unless B has an explicit unwinding
>> destructor.  (Calling a regular destructor from an unwinding one
>> is ok, but the other way round is not.)
>
> An error would be fine with me as would generating an unwinding
> destructor
> sharing the same body as the non-unwinding one but called unwinding
> destructors
> for member and bases (that reminds me what is done to handle virtual
> bases;
> I'm not knowledgeable about ABI enough to know if it can be reused or
> not).
> I'd not be fine with generating an unwinding destructor with an empty
> body.
> It looks too much like an opportunity for errors. Part of me preferred
> the error
> until I though about templates.  I fear that having an error will leads
> template
> writers to routinely provide an unwinding destructor and my guess is
> that it will
> often do just the same as the non-unwinding one in its body. But that
> will spread
> the use of unwinding destructors forcing class writer to do the same
> thing.  This
> could be mitigated by providing a way for template writers to not
> provide unwinding
> destructors if none is needed (and that would be probably useful even
> if there is
> an automatically generated unwinding destructor instead of an error).

We might want to have

   ~S() = default;

generate a regular and an unwinding destructor if and only if they would
differ, i.e. if a base or member has an unwinding destructor.  I think
that addresses the template case nicely.

> One probably also need a way to explicitly call the unwinding
> destructor for cases
> where you separate allocation and lifetime management.
>
> a::~A(1);
>
> is the obvious candidate.

Yes, we need that.

> I'm undecided on the related subject of having version of delete
> calling the unwinding
> destructors, but note that the above facility isn't enough to provide
> the functionality
> because member operator delete are dynamically dispatched.  So
>
> t = new T;
> t->~T(1);
> operator delete(t);
>
> won't do what is needed. (And (*t).operator delete(t) isn't a valid
> alternative).

I'm inclined not to support that at this time.

Jens

--




.


Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Tue, 11 Dec 2012 12:44:25 +0200
Raw View
On 11 December 2012 12:16, Jens Maurer <Jens.Maurer@gmx.net> wrote:
> So, you'd be more in favor of a std::called_from_unwinding() that actually
> does what we want here?  I fear that won't be implementable (easily):
> When does the return value of that function change from "true" to "false"?
> And back?

So.. unwinding here, and in the proposal is unwinding that happens as a result
of a throw, so I would expect called_from_unwinding() to return true
after a throw
expression and false when a handler has been entered. I'm not sure
whether that's
exactly right, but that's my (potentially misguided) starting point.

> Is that a point where the implementation can reasonably inject code to
> effect the return value change?

I must admit I don't know. Is that code injection any different from
injecting code
that chooses which destructor to invoke? I guess at the throw site it isn't, and
at the catch site it would be, since your proposal doesn't require
such injection
at the catch site, if I understand correctly.

I can't help but dislike the potential of opening a can of worms if we
have multiple
destructors.

--




.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Tue, 11 Dec 2012 12:16:44 +0100
Raw View
On 12/11/2012 11:44 AM, Ville Voutilainen wrote:
> On 11 December 2012 12:16, Jens Maurer <Jens.Maurer@gmx.net> wrote:
>> So, you'd be more in favor of a std::called_from_unwinding() that actually
>> does what we want here?  I fear that won't be implementable (easily):
>> When does the return value of that function change from "true" to "false"?
>> And back?
>
> So.. unwinding here, and in the proposal is unwinding that happens as a result
> of a throw, so I would expect called_from_unwinding() to return true
> after a throw
> expression and false when a handler has been entered.

That's exactly what std::uncaught_exception() does, and that's insufficient
(see Herb's GotW #47 article referred to in the paper).   In short,
destructors called during regular scope exit while executing a destructor
due to stack unwinding cannot detect the difference.  This deficiency
is the main motivation for the proposal.

> I can't help but dislike the potential of opening a can of worms if we
> have multiple
> destructors.

An alternative would be to go back to a runtime choice, which probably
kills a few of the worms, including the necessity for "cleanup" functions:

  struct S {
    ~S(bool unwinding);   // cannot co-exist with normal destructor in same class
  }

S::~S(bool) is called with a "true" argument during stack unwinding and with a
"false" argument otherwise.  If a base or member has such a bool destructor,
we call it, forwarding our own argument value.  Otherwise, we call the regular
destructor, essentially dropping the difference on the floor.  Template wrappers
that want to be flexible would always define a bool destructor.  Within the
destructor, the choice between "unwinding" and "regular scope exit" is a
runtime "if", but optimizations such as constant propagation and function cloning
should be able to remove the runtime "if".

It seems this approach would substantially reduce the (compile-time) complexity
and thus the specification complexity, which is good for such a rarely-used
thing.

Jens

--




.


Author: Alberto Ganesh Barbati <albertobarbati@gmail.com>
Date: Tue, 11 Dec 2012 12:19:15 +0100
Raw View
Il giorno 11/dic/2012, alle ore 11:44, Ville Voutilainen <ville.voutilainen=
@gmail.com> ha scritto:

> On 11 December 2012 12:16, Jens Maurer <Jens.Maurer@gmx.net> wrote:
>> So, you'd be more in favor of a std::called_from_unwinding() that actual=
ly
>> does what we want here?  I fear that won't be implementable (easily):
>> When does the return value of that function change from "true" to "false=
"?
>> And back?
>=20
> So.. unwinding here, and in the proposal is unwinding that happens as a r=
esult
> of a throw, so I would expect called_from_unwinding() to return true
> after a throw
> expression and false when a handler has been entered. I'm not sure
> whether that's
> exactly right, but that's my (potentially misguided) starting point.
>=20
>> Is that a point where the implementation can reasonably inject code to
>> effect the return value change?
>=20
> I must admit I don't know. Is that code injection any different from
> injecting code
> that chooses which destructor to invoke? I guess at the throw site it isn=
't, and
> at the catch site it would be, since your proposal doesn't require
> such injection
> at the catch site, if I understand correctly.
>=20
> I can't help but dislike the potential of opening a can of worms if we
> have multiple
> destructors.

Not that I am proposing this, as it clearly has ABI implications that might=
 not be solvable, but why having two destructors? We could have a single de=
structor and pass the context as a parameter:

 ~Transaction(bool unwinding) {
      if (unwinding)
        RollBack();
      else
        Commit();
    }

the value of the parameter is implicitly forwarded to the destructor of sub=
objects, so that the whole chain is provided the correct value, which is de=
termined by the compiler at the original destruction site. If the declared =
destructor doesn't take a parameter, it's passed anyway, simply the functio=
n doesn't have access to it. It is ill-formed to declare both destructors (=
with and without parameter).

Given that the destructor is a very special function, the proposed syntax d=
oesn't mean that the parameter has to be actually passed using the usual ca=
lling conventions, if that might help addressing ABI issues.

Just an idea,

Ganesh

--=20




.


Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Tue, 11 Dec 2012 13:56:30 +0200
Raw View
On 11 December 2012 13:16, Jens Maurer <Jens.Maurer@gmx.net> wrote:
>> So.. unwinding here, and in the proposal is unwinding that happens as a result
>> of a throw, so I would expect called_from_unwinding() to return true
>> after a throw
>> expression and false when a handler has been entered.
> That's exactly what std::uncaught_exception() does, and that's insufficient
> (see Herb's GotW #47 article referred to in the paper).   In short,
> destructors called during regular scope exit while executing a destructor
> due to stack unwinding cannot detect the difference.  This deficiency
> is the main motivation for the proposal.

Ok, this rings a bell, since in Santa Cruz I presented a wishlist item
for being able
to access on-the-fly exceptions, and uncaught_exception +
current_exception can't
do that since they can't know whether the current frame threw. Perhaps we would
need to solve that problem, then, and get multiple benefits rather
than just the rollback
capability.

Please take a look at N2952:
http://open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2952.html

It tries to ruminate on the logging-of-flying-exceptions, perhaps
there are synergies we could
achieve?

--




.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Tue, 11 Dec 2012 15:18:14 +0100
Raw View
On 12/11/2012 12:56 PM, Ville Voutilainen wrote:
> Please take a look at N2952:
> http://open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2952.html
>
> It tries to ruminate on the logging-of-flying-exceptions, perhaps
> there are synergies we could
> achieve?

We could (incompatibly) change the semantics of std::current_exception()
to also work during stack unwinding, and use the new proposed feature
to detect that you're actually called from stack unwinding as opposed
to some other place.

Jens


--




.


Author: stackmachine@hotmail.com
Date: Sat, 15 Dec 2012 02:09:04 -0800 (PST)
Raw View
------=_Part_1150_13169585.1355566144604
Content-Type: text/plain; charset=ISO-8859-1

I like the idea, but the syntax is a bit ugly. I'd prefer something like
this:
struct foo
{
    ~foo() { ... } // regular destructor
    !foo() { ... } // unwinding destructor
};

The runtime choice with a bool parameter seems to introduce unnecessary
overhead.

--




------=_Part_1150_13169585.1355566144604
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

I like the idea, but the syntax is a bit ugly. I'd prefer something like th=
is:<br><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250, =
250); border-color: rgb(187, 187, 187); border-style: solid; border-width: =
1px; word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subp=
rettyprint"><span style=3D"color: #008;" class=3D"styled-by-prettify">struc=
t</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> foo<br><=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; &nbsp; </=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">~</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify">foo</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">()</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">...</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">}</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span=
 style=3D"color: #800;" class=3D"styled-by-prettify">// regular destructor<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; =
&nbsp; </span><span style=3D"color: #660;" class=3D"styled-by-prettify">!</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify">foo</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">()</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">...</span><span style=3D"color: #000;" class=3D"styled=
-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">}</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </s=
pan><span style=3D"color: #800;" class=3D"styled-by-prettify">// unwinding =
destructor</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
<br></span><span style=3D"color: #660;" class=3D"styled-by-prettify">};</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span></d=
iv></code></div><br>The runtime choice with a bool parameter seems to intro=
duce unnecessary overhead.<br>

<p></p>

-- <br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_1150_13169585.1355566144604--

.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Sat, 15 Dec 2012 18:10:46 +0100
Raw View
On 12/15/2012 11:09 AM, stackmachine@hotmail.com wrote:
> I like the idea, but the syntax is a bit ugly. I'd prefer something like this:
> ||
> structfoo
> {
>     ~foo(){...}// regular destructor
>     !foo(){...}// unwinding destructor
> };
>
> The runtime choice with a bool parameter seems to introduce unnecessary overhead.

Earlier in the thread, we discussed
  ~foo(int){...}  // unwinding destructor

which, we believe, has more fallout throughout the language
than the bool parameter.  Your !foo() suggestion is equivalent
to that.  Since this is a feature that will be used in rare cases
only, we should keep the fallout minimal.

I'm sure a compiler can optimize the bool parameter away
by constant propagation and function cloning.

Jens

--




.


Author: =?ISO-8859-1?Q?Daniel_Kr=FCgler?= <daniel.kruegler@gmail.com>
Date: Sat, 15 Dec 2012 18:24:31 +0100
Raw View
2012/12/15  <stackmachine@hotmail.com>:
> I like the idea, but the syntax is a bit ugly. I'd prefer something like
> this:
> struct foo
> {
>     ~foo() { ... } // regular destructor
>     !foo() { ... } // unwinding destructor
> };

Using this choice would break a popular language extension ("managed C++"),
where the above unwinding destructor would refer to a so-called finalizer:

http://msdn.microsoft.com/en-us/library/vstudio/ms177197.aspx

Usually the C++ standard committee tries to minimize such kind of damage to
existing extensions.

Also, I think that the form suggested by Jens (allowing for some parameter type
to be discussed) looks quite natural for the C++ language.

- Daniel

--




.


Author: =?ISO-8859-1?Q?Daniel_Kr=FCgler?= <daniel.kruegler@gmail.com>
Date: Sat, 15 Dec 2012 18:35:46 +0100
Raw View
2012/12/15 Jens Maurer <Jens.Maurer@gmx.net>:
> Earlier in the thread, we discussed
>   ~foo(int){...}  // unwinding destructor
>
> which, we believe, has more fallout throughout the language
> than the bool parameter.  Your !foo() suggestion is equivalent
> to that.  Since this is a feature that will be used in rare cases
> only, we should keep the fallout minimal.
>
> I'm sure a compiler can optimize the bool parameter away
> by constant propagation and function cloning.

I agree that ~foo(int) looks like a consistent choice for C++.

Btw.: It just occurs to me that destructors are not automatically
handled by the general wording for operators, 13.5 p8

"An operator function cannot have default arguments (8.3.6), except
where explicitly stated below."

so the question arises whether we want to allow for

~foo(int = 0){...}

which would call a different destructor for current explicit
destructor calls. At the moment I tend to disallows a default argument
here.

- Daniel

--




.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Sat, 15 Dec 2012 19:34:49 +0100
Raw View
On 12/15/2012 06:35 PM, Daniel Kr=FCgler wrote:
> I agree that ~foo(int) looks like a consistent choice for C++.

Right, but it seems to have more fallout than using
   ~foo(bool)
as the new-style destructor where the value of the parameter
indicates "unwinding" or not.  So, in a sense, traditional
~foo() destructor could become deprecated.

And no, we don't want default arguments.

Jens

--=20




.


Author: Fernando Pelliccioni <fpelliccioni@gmail.com>
Date: Mon, 17 Dec 2012 01:07:30 -0300
Raw View
--f46d044787c527f66004d1048509
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

I wonder if it makes sense the concept of "unwinding destructor" if
something like this were to be approved:

http://cpp-next.com/archive/2012/08/evil-or-just-misunderstood/


On Sat, Dec 15, 2012 at 3:34 PM, Jens Maurer <Jens.Maurer@gmx.net> wrote:

> On 12/15/2012 06:35 PM, Daniel Kr=FCgler wrote:
> > I agree that ~foo(int) looks like a consistent choice for C++.
>
> Right, but it seems to have more fallout than using
>    ~foo(bool)
> as the new-style destructor where the value of the parameter
> indicates "unwinding" or not.  So, in a sense, traditional
> ~foo() destructor could become deprecated.
>
> And no, we don't want default arguments.
>
> Jens
>
> --
>
>
>
>

--=20




--f46d044787c527f66004d1048509
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

<div>I wonder if it makes sense the concept of &quot;unwinding destructor&q=
uot;=A0if something like this were to be approved:</div><div><br></div><a h=
ref=3D"http://cpp-next.com/archive/2012/08/evil-or-just-misunderstood/">htt=
p://cpp-next.com/archive/2012/08/evil-or-just-misunderstood/</a><br>
<div class=3D"gmail_extra"><br><br><div class=3D"gmail_quote">On Sat, Dec 1=
5, 2012 at 3:34 PM, Jens Maurer <span dir=3D"ltr">&lt;<a href=3D"mailto:Jen=
s.Maurer@gmx.net" target=3D"_blank">Jens.Maurer@gmx.net</a>&gt;</span> wrot=
e:<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><div class=3D"im">On 12/15/2012 06:35 PM, Da=
niel Kr=FCgler wrote:<br>
&gt; I agree that ~foo(int) looks like a consistent choice for C++.<br>
<br>
</div>Right, but it seems to have more fallout than using<br>
=A0 =A0~foo(bool)<br>
as the new-style destructor where the value of the parameter<br>
indicates &quot;unwinding&quot; or not. =A0So, in a sense, traditional<br>
~foo() destructor could become deprecated.<br>
<br>
And no, we don&#39;t want default arguments.<br>
<span class=3D"HOEnZb"><font color=3D"#888888"><br>
Jens<br>
<br>
--<br>
<br>
<br>
<br>
</font></span></blockquote></div><br></div>

<p></p>

-- <br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />

--f46d044787c527f66004d1048509--

.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Mon, 17 Dec 2012 09:33:25 +0100
Raw View
On 12/17/2012 05:07 AM, Fernando Pelliccioni wrote:
> I wonder if it makes sense the concept of "unwinding destructor" if somet=
hing like this were to be approved:
>=20
> http://cpp-next.com/archive/2012/08/evil-or-just-misunderstood/

The main article just presents the problem, and concludes:

"This being C++, we expect someone to want more control over that second
exception, so in our next installment, we=92ll consider some alternatives."

So there isn't actually a suggestion in there to approve.

I didn't wade through the forest of comments.

Jens

--=20




.


Author: Olaf van der Spek <olafvdspek@gmail.com>
Date: Mon, 17 Dec 2012 05:41:24 -0800 (PST)
Raw View
------=_Part_889_5023808.1355751684734
Content-Type: text/plain; charset=ISO-8859-1

Op dinsdag 11 december 2012 11:19:34 UTC+1 schreef Jens Maurer het volgende:

> On 12/11/2012 12:04 AM, Olaf van der Spek wrote:
> > It's just about the example, I hope you don't mind:
> > What about rolling back the transaction unless explicitly commited?
>
> That's a design choice you can make.  With current C++11, it seems to
> be the only reasonable design choice.
>

If a reasonable solution exist, is it still worth all the trouble to try to
support the other choice?


>
>

--




------=_Part_889_5023808.1355751684734
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

Op dinsdag 11 december 2012 11:19:34 UTC+1 schreef Jens Maurer het volgende=
:<br><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8e=
x;border-left: 1px #ccc solid;padding-left: 1ex;">On 12/11/2012 12:04 AM, O=
laf van der Spek wrote:
<br>&gt; It's just about the example, I hope you don't mind:
<br>&gt; What about rolling back the transaction unless explicitly commited=
?
<br>
<br>That's a design choice you can make. &nbsp;With current C++11, it seems=
 to
<br>be the only reasonable design choice.
<br></blockquote><div><br></div><div>If a reasonable solution exist, is it =
still worth all the trouble to try to support the other choice?</div><div>&=
nbsp;<br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-=
left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">&nbsp;<br></blo=
ckquote>

<p></p>

-- <br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_889_5023808.1355751684734--

.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Mon, 17 Dec 2012 20:36:49 +0100
Raw View
On 12/17/2012 02:41 PM, Olaf van der Spek wrote:
> Op dinsdag 11 december 2012 11:19:34 UTC+1 schreef Jens Maurer het volgende:
>
>     On 12/11/2012 12:04 AM, Olaf van der Spek wrote:
>     > It's just about the example, I hope you don't mind:
>     > What about rolling back the transaction unless explicitly commited?
>
>     That's a design choice you can make.  With current C++11, it seems to
>     be the only reasonable design choice.
>
>
> If a reasonable solution exist, is it still worth all the trouble to try to support the other choice?

Good question.

Possible answers:

 - Note that intermediate "return" or "break" statements could make
you leave the transaction scope with the intention to commit.
Requiring every such code path to explicitly say "commit" seems
error-prone; you might overlook a rarely-executed code path.

 - Given that the programmer already has to write "transaction t(...)" in her
program, why is it necessary to explicitly state "t.commit()"?  This violates
a bit the RAII idiom (which is only approximately applicable here).

 - I think there are situations where you exactly need to distinguish
whether throwing from a destructor invocation will surely call std::terminate,
or not.

 - Emulation of the "D" language scope(exit) and scope(failure) features
requires the differentiation.

Jens

--




.


Author: Zhihao Yuan <lichray@gmail.com>
Date: Mon, 17 Dec 2012 15:57:40 -0600
Raw View
On Mon, Dec 17, 2012 at 1:36 PM, Jens Maurer <Jens.Maurer@gmx.net> wrote:
>  - Note that intermediate "return" or "break" statements could make
> you leave the transaction scope with the intention to commit.
> Requiring every such code path to explicitly say "commit" seems
> error-prone; you might overlook a rarely-executed code path.

"Commit" is different from releasing; you only need it at _one_ safe place, not
multiple unsafe places.  It works for both local and non-local jump.

>  - Emulation of the "D" language scope(exit) and scope(failure) features
> requires the differentiation.

scope(failure) is nice, but it's not that easy to use (and hard to
read...).  Since it
only works for non-local jump, you have to protect local jump (non-exception
failures) by yourself.  A "commit()" can be more explicit.

However, I do +1 for your idea and even throwable destructors.  A detectable
unwinding makes things clean, that's my feeling.

--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://4bsd.biz/

--




.


Author: Aleksandar Fabijanic <aleks.fabijanic@gmail.com>
Date: Mon, 17 Dec 2012 15:59:39 -0600
Raw View
On Mon, Dec 17, 2012 at 7:41 AM, Olaf van der Spek <olafvdspek@gmail.com> wrote:
> Op dinsdag 11 december 2012 11:19:34 UTC+1 schreef Jens Maurer het volgende:
>
>> On 12/11/2012 12:04 AM, Olaf van der Spek wrote:
>> > It's just about the example, I hope you don't mind:
>> > What about rolling back the transaction unless explicitly commited?
>>
>> That's a design choice you can make.  With current C++11, it seems to
>> be the only reasonable design choice.
>
> If a reasonable solution exist, is it still worth all the trouble to try to
> support the other choice?

This is a real world problem and current solutions do not quite cut it
all the way. I'd go further than original proposal - what would be
really valuable is, instead of dummy int, to have the actual exception
passed to the destructor - before deciding and attempting
commit/rollback, you'd want to know whether it makes sense to attempt
either. For example, if the uncaught exception was due to loss of
database connection then attempting neither makes sense. If there is a
destructor with argument that matches (rules same as for catch()
matching) the exception thrown, it is called; if not, the default
destructor is called.

~T() { // clean scope exit
  try { commit(); }
  catch(...) { }
}

~T(const std::exception& e) {
  try { rollback(); }
  catch(...) { }
}

~T(const conn_lost_exc& c) {
  // neither rollback nor commit make sense ...
}

I have no idea how difficult would this be to implement, but it would
be really nice to have.

Alex

--




.


Author: Nevin Liber <nevin@eviloverlord.com>
Date: Mon, 17 Dec 2012 16:03:32 -0600
Raw View
--bcaec554d29ae64b3204d1138fdf
Content-Type: text/plain; charset=ISO-8859-1

On 17 December 2012 15:59, Aleksandar Fabijanic
<aleks.fabijanic@gmail.com>wrote:

> This is a real world problem and current solutions do not quite cut it
> all the way. I'd go further than original proposal - what would be
> really valuable is, instead of dummy int, to have the actual exception
> passed to the destructor - before deciding and attempting
> commit/rollback, you'd want to know whether it makes sense to attempt
> either.


That would be interesting...


> For example, if the uncaught exception was due to loss of
> database connection then attempting neither makes sense. If there is a
> destructor with argument that matches (rules same as for catch()
> matching) the exception thrown, it is called; if not, the default
> destructor is called.
>

So, you are proposing that declaration order of destructors would matter
(since that is what happens with catch clauses)?
--
 Nevin ":-)" Liber  <mailto:nevin@eviloverlord.com>  (847) 691-1404

--




--bcaec554d29ae64b3204d1138fdf
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

On 17 December 2012 15:59, Aleksandar Fabijanic <span dir=3D"ltr">&lt;<a hr=
ef=3D"mailto:aleks.fabijanic@gmail.com" target=3D"_blank">aleks.fabijanic@g=
mail.com</a>&gt;</span> wrote:<br><div class=3D"gmail_quote"><blockquote cl=
ass=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;p=
adding-left:1ex">

<div class=3D"HOEnZb"><div class=3D"h5">This is a real world problem and cu=
rrent solutions do not quite cut it</div></div>
all the way. I&#39;d go further than original proposal - what would be<br>
really valuable is, instead of dummy int, to have the actual exception<br>
passed to the destructor - before deciding and attempting<br>
commit/rollback, you&#39;d want to know whether it makes sense to attempt<b=
r>
either. </blockquote><div><br></div><div>That would be interesting...</div>=
<div>=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;=
border-left:1px #ccc solid;padding-left:1ex">For example, if the uncaught e=
xception was due to loss of<br>


database connection then attempting neither makes sense. If there is a<br>
destructor with argument that matches (rules same as for catch()<br>
matching) the exception thrown, it is called; if not, the default<br>
destructor is called.<br></blockquote><div><br></div><div>So, you are propo=
sing that declaration order of destructors would matter (since that is what=
 happens with catch clauses)?</div><div>--=A0</div></div>=A0Nevin &quot;:-)=
&quot; Liber=A0 &lt;mailto:<a href=3D"mailto:nevin@eviloverlord.com" target=
=3D"_blank">nevin@eviloverlord.com</a>&gt;=A0 (847) 691-1404<br>


<p></p>

-- <br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />

--bcaec554d29ae64b3204d1138fdf--

.


Author: =?UTF-8?Q?Klaim_=2D_Jo=C3=ABl_Lamotte?= <mjklaim@gmail.com>
Date: Mon, 17 Dec 2012 23:05:08 +0100
Raw View
--f46d042f9c2612d1cb04d1139331
Content-Type: text/plain; charset=ISO-8859-1

On Mon, Dec 17, 2012 at 10:59 PM, Aleksandar Fabijanic <
aleks.fabijanic@gmail.com> wrote:

> I have no idea how difficult would this be to implement, but it would
> be really nice to have.
>


Doesn't it force the compiler to generate try/catch code for all
destructors?

Joel Lamotte

--




--f46d042f9c2612d1cb04d1139331
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div class=3D"gmail_extra"><br><br><div class=3D"gmail_quo=
te">On Mon, Dec 17, 2012 at 10:59 PM, Aleksandar Fabijanic <span dir=3D"ltr=
">&lt;<a href=3D"mailto:aleks.fabijanic@gmail.com" target=3D"_blank">aleks.=
fabijanic@gmail.com</a>&gt;</span> wrote:<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><div id=3D":2lq">I have no idea how difficul=
t would this be to implement, but it would<br>
be really nice to have.</div></blockquote></div><br></div><div class=3D"gma=
il_extra"><br></div><div class=3D"gmail_extra" style>Doesn&#39;t it force t=
he compiler to generate try/catch code for all destructors?</div><div class=
=3D"gmail_extra" style>
<br></div><div class=3D"gmail_extra" style>Joel Lamotte</div><div class=3D"=
gmail_extra" style><br></div></div>

<p></p>

-- <br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />

--f46d042f9c2612d1cb04d1139331--

.


Author: Aleksandar Fabijanic <aleks.fabijanic@gmail.com>
Date: Mon, 17 Dec 2012 16:22:12 -0600
Raw View
On Mon, Dec 17, 2012 at 4:03 PM, Nevin Liber <nevin@eviloverlord.com> wrote:
> On 17 December 2012 15:59, Aleksandar Fabijanic <aleks.fabijanic@gmail.com>
> wrote:

> So, you are proposing that declaration order of destructors would matter
> (since that is what happens with catch clauses)?

I'd prefer it to find a best match regardless of order but whether
that is feasible woud be a question for someone well versed in
compiler implementation.

--




.


Author: Aleksandar Fabijanic <aleks.fabijanic@gmail.com>
Date: Mon, 17 Dec 2012 16:27:37 -0600
Raw View
On Mon, Dec 17, 2012 at 4:05 PM, Klaim - Jo=EBl Lamotte <mjklaim@gmail.com>=
 wrote:
>
> On Mon, Dec 17, 2012 at 10:59 PM, Aleksandar Fabijanic
> <aleks.fabijanic@gmail.com> wrote:
>>
>> I have no idea how difficult would this be to implement, but it would
>> be really nice to have.
>
> Doesn't it force the compiler to generate try/catch code for all
> destructors?

At the place where regular scope exit destructor is called, things
would be the same as they've always been. Elsewhere, wherever the
destructor is invoked, there would have to be logic to decide which
one exactly to invoke.

Alex

--=20




.


Author: Olaf van der Spek <olafvdspek@gmail.com>
Date: Tue, 18 Dec 2012 01:03:57 +0100
Raw View
On Mon, Dec 17, 2012 at 8:36 PM, Jens Maurer <Jens.Maurer@gmx.net> wrote:
> On 12/17/2012 02:41 PM, Olaf van der Spek wrote:
>> Op dinsdag 11 december 2012 11:19:34 UTC+1 schreef Jens Maurer het volgende:
>>
>>     On 12/11/2012 12:04 AM, Olaf van der Spek wrote:
>>     > It's just about the example, I hope you don't mind:
>>     > What about rolling back the transaction unless explicitly commited?
>>
>>     That's a design choice you can make.  With current C++11, it seems to
>>     be the only reasonable design choice.
>>
>>
>> If a reasonable solution exist, is it still worth all the trouble to try to support the other choice?
>
> Good question.
>
> Possible answers:
>
>  - Note that intermediate "return" or "break" statements could make
> you leave the transaction scope with the intention to commit.

Or the intention could be to rollback.

> Requiring every such code path to explicitly say "commit" seems
> error-prone; you might overlook a rarely-executed code path.

Usually there are more error exits and less non-error exits.
Non-error exits also tend to be tested better.

What's worse? An accidentally commited transaction or an accidentally
rolled back one?

>  - Given that the programmer already has to write "transaction t(...)" in her
> program, why is it necessary to explicitly state "t.commit()"?

Because there's a choice: commit or rollback. And IMO there's only one
safe default.

> This violates
> a bit the RAII idiom (which is only approximately applicable here).

That's about releasing resources, not about committing or rolling back.

>  - I think there are situations where you exactly need to distinguish
> whether throwing from a destructor invocation will surely call std::terminate,
> or not.
>
>  - Emulation of the "D" language scope(exit) and scope(failure) features
> requires the differentiation.

Copying features without looking at the problems they solve isn't good design.

--
Olaf

--




.


Author: Sebastian Gesemann <s.gesemann@gmail.com>
Date: Mon, 17 Dec 2012 13:42:56 +0100
Raw View
On Mon, Dec 10, 2012 at 5:32 PM, Jens Maurer wrote:
>
> Here's a proposal to offer a core feature where
> std::uncaught_exception() fails.  Also available at
> http://jmaurer.awardspace.info/wg21/destructor-unwinding.html .

from your proposal:
>
> struct Transaction {
>     Transaction();
>     ~Transaction() {
>       if (std::uncaught_exception())
>         RollBack();
>       else
>         Commit();
>     }
>  };
>
> The well-intended meaning was for a transaction to roll back if its
> scope was exited via an exception. However, this detection is
> unreliable for the following usage:
>
>   U::~U(int) {
>     try {
>       Transaction t( /*...*/ );
>       // do work
>     } catch( ... ) {
>       // clean up
>     }
>   }
>
> If U::~U() is called during stack unwinding, the transaction inside
> will always roll back, although "commit" was expected. Note that the
> the transaction construct could appear in a called function that is
> not (and should not be) aware of the context from which it is called.

If there was a way to compare uncaught exceptions, there would be
another solution:

  - ask runtime about an uncaught exception during the
    CONSTRUCTION of the Transaction object

  - ask runtime about an uncaught exception during the
    DESTRUCTION of the Transaction object

  - If we have a new uncaught exception at destruction
    (different from a possible one at construction time)
    we're in stack-unwinding mode.

for now, this does not seem possible because std::current_exception
only returns a non-null exception_ptr for HANDLED exceptions and not
for uncaught exceptions, as far as I can tell. Otherwise we could write
something like this:

   class UnwindDetector
   {
   public:
      UnwindDetector();
      : atinit(std::current_exception())
      {}
      bool unwinding() const
      { return std::uncaught_exception()
        && (atinit != std::current_exception());
      }
   private:
      std::exception_ptr atinit;
   };

   struct Transaction
   {
      UnwindDetector uwd;
      Transaction();
      ~Transaction()
      {  if (uwd.unwinding())
            RollBack();
         else
            Commit();
      }
   };

Cheers!
SG

--




.


Author: Fernando Cacciola <fernando.cacciola@gmail.com>
Date: Fri, 21 Dec 2012 13:23:03 -0300
Raw View
On Mon, Dec 17, 2012 at 9:42 AM, Sebastian Gesemann
<s.gesemann@gmail.com> wrote:
> On Mon, Dec 10, 2012 at 5:32 PM, Jens Maurer wrote:
>
>    class UnwindDetector
>    {
>    public:
>       UnwindDetector();
>       : atinit(std::current_exception())
>       {}
>       bool unwinding() const
>       { return std::uncaught_exception()
>         && (atinit != std::current_exception());
>       }
>    private:
>       std::exception_ptr atinit;
>    };
>
>    struct Transaction
>    {
>       UnwindDetector uwd;
>       Transaction();
>       ~Transaction()
>       {  if (uwd.unwinding())
>             RollBack();
>          else
>             Commit();
>       }
>    };
>

Interesting...

I like the original proposal of having two destructors because it is
quite clear what it is about.
And then I like the form taking the bool such that the regular dtor
would not even be implemented when the other is needed.

However, this solution would also get the job done AFAICT. And it also
provides a way to determine what exactly is happening, like Aleksandar
proposed, even if via RTTI as opposed to a direct dispatching resolved
by the compiler. So, it seems to me that this is a better solution.

Lastly, I've been wondering if there could be a use case when I am in
a normal scope exit destructor BUT within an unwinding destructor, and
I want to know that and use a strategy closer to the unwinding than
the normal exit. In that case, the separate dtros would get in the way
while this solution would give me all the information I want.



--
Fernando Cacciola
SciSoft Consulting, Founder
http://www.scisoft-consulting.com

--




.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Sat, 22 Dec 2012 08:10:33 +0100
Raw View
On 12/17/2012 01:42 PM, Sebastian Gesemann wrote:
> for now, this does not seem possible because std::current_exception
> only returns a non-null exception_ptr for HANDLED exceptions and not
> for uncaught exceptions, as far as I can tell. Otherwise we could write
> something like this:
>
>    class UnwindDetector
>    {
>    public:
>       UnwindDetector();
>       : atinit(std::current_exception())
>       {}
>       bool unwinding() const
>       { return std::uncaught_exception()
>         && (atinit != std::current_exception());
>       }
>    private:
>       std::exception_ptr atinit;
>    };


std::current_exception() may return a copy of the original exception,
so the comparison might not do the right thing.

It seems this approach is fragile.

Jens


--




.


Author: Alberto Barbati <albertobarbati@gmail.com>
Date: Sat, 22 Dec 2012 18:39:51 +0100
Raw View
--Apple-Mail-962A9903-A76C-42BA-B28D-1524430C5044
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable


Il giorno 22/dic/2012, alle ore 08:10, Jens Maurer <Jens.Maurer@gmx.net> ha=
 scritto:

> On 12/17/2012 01:42 PM, Sebastian Gesemann wrote:
>> for now, this does not seem possible because std::current_exception
>> only returns a non-null exception_ptr for HANDLED exceptions and not
>> for uncaught exceptions, as far as I can tell. Otherwise we could write
>> something like this:
>>=20
>>  class UnwindDetector
>>  {
>>  public:
>>     UnwindDetector();
>>     : atinit(std::current_exception())
>>     {}
>>     bool unwinding() const
>>     { return std::uncaught_exception()
>>       && (atinit !=3D std::current_exception());
>>     }
>>  private:
>>     std::exception_ptr atinit;
>>  };
>=20
>=20
> std::current_exception() may return a copy of the original exception,
> so the comparison might not do the right thing.
>=20
> It seems this approach is fragile.

It is fragile, but it is still very insightful. First of all, I believe the=
 following easier approach should actually work:

struct Transaction
  {
     bool uncaught_exception_at_ctor;
     Transaction()
     {
       uncaught_exception_at_ctor =3D uncaught_exception();
     }
     ~Transaction()
     {  if (uncaught_exception() and not uncaught_exception_at_ctor)
           RollBack();
        else
           Commit();
     }
  };

Notice that if uncaught_exception_at_ctor is true, Commit() is always calle=
d. That is based on the assumption that in that case the dtor will never be=
 invoked as part of a stack unwinding: any throw that might trigger it woul=
d call terminate() instead.=20

Even if my approach is proved not to work, the example shows that a pure li=
brary approach might actually be implementable. The key point is that the f=
acility has to be splitted in two functions: one to call in the ctor and on=
e in the dtor. An alternative design could be similar to class UnwindDetect=
or itself.

Just my two eurocent,

Ganesh=20

--=20




--Apple-Mail-962A9903-A76C-42BA-B28D-1524430C5044
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

<html><head><meta http-equiv=3D"content-type" content=3D"text/html; charset=
=3Dutf-8"></head><body dir=3D"auto"><div><span></span></div><div><meta http=
-equiv=3D"content-type" content=3D"text/html; charset=3Dutf-8"><div><span><=
/span></div><div><meta http-equiv=3D"content-type" content=3D"text/html; ch=
arset=3Dutf-8"><div style=3D"-webkit-text-size-adjust: auto; "><span></span=
></div><div><span style=3D"-webkit-text-size-adjust: auto;"></span><br><spa=
n style=3D"-webkit-text-size-adjust: auto; ">Il giorno 22/dic/2012, alle or=
e 08:10, Jens Maurer &lt;<a href=3D"mailto:Jens.Maurer@gmx.net">Jens.Maurer=
@gmx.net</a>&gt; ha scritto:</span><br><span style=3D"-webkit-text-size-adj=
ust: auto;"></span><br><blockquote type=3D"cite" style=3D"-webkit-text-size=
-adjust: auto; "><span>On 12/17/2012 01:42 PM, Sebastian Gesemann wrote:</s=
pan><br></blockquote><blockquote type=3D"cite" style=3D"-webkit-text-size-a=
djust: auto; "><blockquote type=3D"cite"><span>for now, this does not seem =
possible because std::current_exception</span><br></blockquote></blockquote=
><blockquote type=3D"cite" style=3D"-webkit-text-size-adjust: auto; "><bloc=
kquote type=3D"cite"><span>only returns a non-null exception_ptr for HANDLE=
D exceptions and not</span><br></blockquote></blockquote><blockquote type=
=3D"cite" style=3D"-webkit-text-size-adjust: auto; "><blockquote type=3D"ci=
te"><span>for uncaught exceptions, as far as I can tell. Otherwise we could=
 write</span><br></blockquote></blockquote><blockquote type=3D"cite" style=
=3D"-webkit-text-size-adjust: auto; "><blockquote type=3D"cite"><span>somet=
hing like this:</span><br></blockquote></blockquote><blockquote type=3D"cit=
e" style=3D"-webkit-text-size-adjust: auto; "><blockquote type=3D"cite"><sp=
an></span><br></blockquote></blockquote><blockquote type=3D"cite" style=3D"=
-webkit-text-size-adjust: auto; "><blockquote type=3D"cite"><span> &nbsp;cl=
ass UnwindDetector</span><br></blockquote></blockquote><blockquote type=3D"=
cite" style=3D"-webkit-text-size-adjust: auto; "><blockquote type=3D"cite">=
<span> &nbsp;{</span><br></blockquote></blockquote><blockquote type=3D"cite=
" style=3D"-webkit-text-size-adjust: auto; "><blockquote type=3D"cite"><spa=
n> &nbsp;public:</span><br></blockquote></blockquote><blockquote type=3D"ci=
te" style=3D"-webkit-text-size-adjust: auto; "><blockquote type=3D"cite"><s=
pan> &nbsp;&nbsp;&nbsp;&nbsp;UnwindDetector();</span><br></blockquote></blo=
ckquote><blockquote type=3D"cite" style=3D"-webkit-text-size-adjust: auto; =
"><blockquote type=3D"cite"><span> &nbsp;&nbsp;&nbsp;&nbsp;: atinit(std::cu=
rrent_exception())</span><br></blockquote></blockquote><blockquote type=3D"=
cite" style=3D"-webkit-text-size-adjust: auto; "><blockquote type=3D"cite">=
<span> &nbsp;&nbsp;&nbsp;&nbsp;{}</span><br></blockquote></blockquote><bloc=
kquote type=3D"cite" style=3D"-webkit-text-size-adjust: auto; "><blockquote=
 type=3D"cite"><span> &nbsp;&nbsp;&nbsp;&nbsp;bool unwinding() const</span>=
<br></blockquote></blockquote><blockquote type=3D"cite" style=3D"-webkit-te=
xt-size-adjust: auto; "><blockquote type=3D"cite"><span> &nbsp;&nbsp;&nbsp;=
&nbsp;{ return std::uncaught_exception()</span><br></blockquote></blockquot=
e><blockquote type=3D"cite" style=3D"-webkit-text-size-adjust: auto; "><blo=
ckquote type=3D"cite"><span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&amp;&amp;=
 (atinit !=3D std::current_exception());</span><br></blockquote></blockquot=
e><blockquote type=3D"cite" style=3D"-webkit-text-size-adjust: auto; "><blo=
ckquote type=3D"cite"><span> &nbsp;&nbsp;&nbsp;&nbsp;}</span><br></blockquo=
te></blockquote><blockquote type=3D"cite" style=3D"-webkit-text-size-adjust=
: auto; "><blockquote type=3D"cite"><span> &nbsp;private:</span><br></block=
quote></blockquote><blockquote type=3D"cite" style=3D"-webkit-text-size-adj=
ust: auto; "><blockquote type=3D"cite"><span> &nbsp;&nbsp;&nbsp;&nbsp;std::=
exception_ptr atinit;</span><br></blockquote></blockquote><blockquote type=
=3D"cite" style=3D"-webkit-text-size-adjust: auto; "><blockquote type=3D"ci=
te"><span> &nbsp;};</span><br></blockquote></blockquote><blockquote type=3D=
"cite" style=3D"-webkit-text-size-adjust: auto; "><span></span><br></blockq=
uote><blockquote type=3D"cite" style=3D"-webkit-text-size-adjust: auto; "><=
span></span><br></blockquote><blockquote type=3D"cite" style=3D"-webkit-tex=
t-size-adjust: auto; "><span>std::current_exception() may return a copy of =
the original exception,</span><br></blockquote><blockquote type=3D"cite" st=
yle=3D"-webkit-text-size-adjust: auto; "><span>so the comparison might not =
do the right thing.</span><br></blockquote><blockquote type=3D"cite" style=
=3D"-webkit-text-size-adjust: auto; "><span></span><br></blockquote><blockq=
uote type=3D"cite" style=3D"-webkit-text-size-adjust: auto; "><span>It seem=
s this approach is fragile.</span><br></blockquote><span style=3D"-webkit-t=
ext-size-adjust: auto;"></span><br><span style=3D"-webkit-text-size-adjust:=
 auto; ">It is fragile, but it is still very insightful. First of all, I be=
lieve the following easier approach should actually work:</span><br><br><sp=
an style=3D"-webkit-text-size-adjust: auto;"></span><div><font color=3D"#00=
0000"><span style=3D"-webkit-text-size-adjust: auto; background-color: rgba=
(255, 255, 255, 0);">struct Transaction<br></span></font></div><div><font c=
olor=3D"#000000"><span style=3D"-webkit-text-size-adjust: auto; background-=
color: rgba(255, 255, 255, 0);">&nbsp;&nbsp;{<br></span></font></div><div><=
font color=3D"#000000"><span style=3D"-webkit-text-size-adjust: auto; backg=
round-color: rgba(255, 255, 255, 0);">&nbsp; &nbsp; &nbsp;bool&nbsp;</span>=
</font><span style=3D"-webkit-tap-highlight-color: rgba(26, 26, 26, 0.29296=
9); -webkit-composition-fill-color: rgba(175, 192, 227, 0.230469); -webkit-=
composition-frame-color: rgba(77, 128, 180, 0.230469); ">uncaught_exception=
_at_ctor</span><font color=3D"#000000"><span style=3D"-webkit-text-size-adj=
ust: auto; background-color: rgba(255, 255, 255, 0);">;<br></span></font></=
div><div><font color=3D"#000000"><span style=3D"-webkit-text-size-adjust: a=
uto; background-color: rgba(255, 255, 255, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;Transaction()<br></span></font></div><div><span style=3D"-webkit-tap-hig=
hlight-color: rgba(26, 26, 26, 0.292969); -webkit-composition-fill-color: r=
gba(175, 192, 227, 0.230469); -webkit-composition-frame-color: rgba(77, 128=
, 180, 0.230469); ">&nbsp; &nbsp; &nbsp;</span><font color=3D"#000000"><spa=
n style=3D"-webkit-text-size-adjust: auto; background-color: rgba(255, 255,=
 255, 0);">{</span></font></div><div><span style=3D"-webkit-tap-highlight-c=
olor: rgba(26, 26, 26, 0.292969); -webkit-composition-fill-color: rgba(175,=
 192, 227, 0.230469); -webkit-composition-frame-color: rgba(77, 128, 180, 0=
..230469); ">&nbsp; &nbsp; &nbsp;</span><font color=3D"#000000"><span style=
=3D"-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0=
);">&nbsp;&nbsp;</span></font><span style=3D"-webkit-tap-highlight-color: r=
gba(26, 26, 26, 0.292969); -webkit-composition-fill-color: rgba(175, 192, 2=
27, 0.230469); -webkit-composition-frame-color: rgba(77, 128, 180, 0.230469=
); ">uncaught_exception_at_ctor =3D&nbsp;</span><span style=3D"-webkit-tap-=
highlight-color: rgba(26, 26, 26, 0.292969); -webkit-composition-fill-color=
: rgba(175, 192, 227, 0.230469); -webkit-composition-frame-color: rgba(77, =
128, 180, 0.230469); ">uncaught_exception();</span></div><div><span style=
=3D"-webkit-tap-highlight-color: rgba(26, 26, 26, 0.292969); -webkit-compos=
ition-fill-color: rgba(175, 192, 227, 0.230469); -webkit-composition-frame-=
color: rgba(77, 128, 180, 0.230469); ">&nbsp; &nbsp; &nbsp;</span><font col=
or=3D"#000000"><span style=3D"-webkit-text-size-adjust: auto; background-co=
lor: rgba(255, 255, 255, 0);">}</span></font></div><div><font color=3D"#000=
000"><span style=3D"-webkit-text-size-adjust: auto; background-color: rgba(=
255, 255, 255, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;~Transaction()<br></span>=
</font></div><div><font color=3D"#000000"><span style=3D"-webkit-text-size-=
adjust: auto; background-color: rgba(255, 255, 255, 0);">&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp;{ &nbsp;if (</span></font><span style=3D"-webkit-tap-highlight-=
color: rgba(26, 26, 26, 0.292969); -webkit-composition-fill-color: rgba(175=
, 192, 227, 0.230469); -webkit-composition-frame-color: rgba(77, 128, 180, =
0.230469); ">uncaught_exception() and not&nbsp;</span><span style=3D"-webki=
t-tap-highlight-color: rgba(26, 26, 26, 0.292969); -webkit-composition-fill=
-color: rgba(175, 192, 227, 0.230469); -webkit-composition-frame-color: rgb=
a(77, 128, 180, 0.230469); ">uncaught_exception_at_ctor)</span></div><div><=
font color=3D"#000000"><span style=3D"-webkit-text-size-adjust: auto; backg=
round-color: rgba(255, 255, 255, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RollBack();<br></span></font></div><div><font =
color=3D"#000000"><span style=3D"-webkit-text-size-adjust: auto; background=
-color: rgba(255, 255, 255, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp;else<br></span></font></div><div><font color=3D"#000000"><span style=
=3D"-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0=
);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Commi=
t();<br></span></font></div><div><font color=3D"#000000"><span style=3D"-we=
bkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;}<br></span></font></div><div><font color=3D"#00=
0000"><span style=3D"-webkit-text-size-adjust: auto; background-color: rgba=
(255, 255, 255, 0);">&nbsp;&nbsp;};</span></font></div></div></div><div><fo=
nt color=3D"#000000"><span style=3D"-webkit-text-size-adjust: auto; backgro=
und-color: rgba(255, 255, 255, 0);"><br></span></font></div><div><font colo=
r=3D"#000000"><span style=3D"-webkit-text-size-adjust: auto; background-col=
or: rgba(255, 255, 255, 0);">Notice that if&nbsp;</span></font><span style=
=3D"-webkit-tap-highlight-color: rgba(26, 26, 26, 0.292969); -webkit-compos=
ition-fill-color: rgba(175, 192, 227, 0.230469); -webkit-composition-frame-=
color: rgba(77, 128, 180, 0.230469); ">uncaught_exception_at_ctor is true, =
Commit() is always called. That is based on the assumption that in that cas=
e the dtor will never be invoked as part of a stack unwinding: any throw th=
at might trigger it would call terminate() instead.&nbsp;</span></div><div>=
<span style=3D"-webkit-tap-highlight-color: rgba(26, 26, 26, 0.292969); -we=
bkit-composition-fill-color: rgba(175, 192, 227, 0.230469); -webkit-composi=
tion-frame-color: rgba(77, 128, 180, 0.230469); "><br></span></div><div><sp=
an style=3D"-webkit-tap-highlight-color: rgba(26, 26, 26, 0.292969); -webki=
t-composition-fill-color: rgba(175, 192, 227, 0.230469); -webkit-compositio=
n-frame-color: rgba(77, 128, 180, 0.230469); ">Even if my approach is prove=
d not to work, the example shows that a pure library approach might actuall=
y be implementable. The key point is that the facility has to be splitted i=
n two functions: one to call in the ctor and one in the dtor. An alternativ=
e design could be similar to class UnwindDetector itself.</span></div><div>=
<span style=3D"-webkit-tap-highlight-color: rgba(26, 26, 26, 0.292969); -we=
bkit-composition-fill-color: rgba(175, 192, 227, 0.230469); -webkit-composi=
tion-frame-color: rgba(77, 128, 180, 0.230469); "><br></span></div><div><sp=
an style=3D"-webkit-tap-highlight-color: rgba(26, 26, 26, 0.292969); -webki=
t-composition-fill-color: rgba(175, 192, 227, 0.230469); -webkit-compositio=
n-frame-color: rgba(77, 128, 180, 0.230469); ">Just my two eurocent,</span>=
</div><div><span style=3D"-webkit-tap-highlight-color: rgba(26, 26, 26, 0.2=
92969); -webkit-composition-fill-color: rgba(175, 192, 227, 0.230469); -web=
kit-composition-frame-color: rgba(77, 128, 180, 0.230469); "><br></span></d=
iv><div><span style=3D"-webkit-tap-highlight-color: rgba(26, 26, 26, 0.2929=
69); -webkit-composition-fill-color: rgba(175, 192, 227, 0.230469); -webkit=
-composition-frame-color: rgba(77, 128, 180, 0.230469); ">Ganesh&nbsp;</spa=
n></div></div></body></html>

<p></p>

-- <br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />

--Apple-Mail-962A9903-A76C-42BA-B28D-1524430C5044--

.


Author: Alberto Barbati <albertobarbati@gmail.com>
Date: Sun, 23 Dec 2012 10:19:33 +0100
Raw View
--Apple-Mail-DB529632-9CF1-4D5A-942D-2829D3CCF625
Content-Type: text/plain; charset=ISO-8859-1


Il giorno 22/dic/2012, alle ore 18:39, Alberto Barbati <albertobarbati@gmail.com> ha scritto:

> First of all, I believe the following easier approach should actually work:
>
> struct Transaction
>   {
>      bool uncaught_exception_at_ctor;
>      Transaction()
>      {
>        uncaught_exception_at_ctor = uncaught_exception();
>      }
>      ~Transaction()
>      {  if (uncaught_exception() and not uncaught_exception_at_ctor)
>            RollBack();
>         else
>            Commit();
>      }
>   };

I take it back. It does not work, I don't know what was I thinking... However, if the implementation could maintain a count of the exceptions thrown but not yet handled (instead of the mere boolean retrieved via uncaught_exception) we might write this:

struct Transaction
  {
     bool ue_count_at_ctor;
     Transaction()
     {
       ue_count_at_ctor = uncaught_exception_count();
     }
     ~Transaction()
     {  if (ue_count_at_ctor < uncaught_exception_count())
           RollBack();
        else
           Commit();
     }
  };

I believe uncaught_exception_count() could be implementable without significant added cost: just increment a per-thread counter upon throw and decrement it upon entering a handler. Is this approach worth considering?

Ganesh

--




--Apple-Mail-DB529632-9CF1-4D5A-942D-2829D3CCF625
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

<html><head><meta http-equiv=3D"content-type" content=3D"text/html; charset=
=3Dutf-8"></head><body dir=3D"auto"><div style=3D"-webkit-text-size-adjust:=
 auto; "><br></div><div style=3D"-webkit-text-size-adjust: auto; ">Il giorn=
o 22/dic/2012, alle ore 18:39, Alberto Barbati &lt;<a href=3D"mailto:albert=
obarbati@gmail.com">albertobarbati@gmail.com</a>&gt; ha scritto:<br><br></d=
iv><blockquote type=3D"cite" style=3D"-webkit-text-size-adjust: auto; "><sp=
an style=3D"-webkit-text-size-adjust: auto; ">First of all, I believe the f=
ollowing easier approach should actually work:</span><br><br><span style=3D=
"-webkit-text-size-adjust: auto;"></span><div><font color=3D"#000000"><span=
 style=3D"-webkit-text-size-adjust: auto; background-color: rgba(255, 255, =
255, 0);">struct Transaction<br></span></font></div><div><font color=3D"#00=
0000"><span style=3D"-webkit-text-size-adjust: auto; background-color: rgba=
(255, 255, 255, 0);">&nbsp;&nbsp;{<br></span></font></div><div><font color=
=3D"#000000"><span style=3D"-webkit-text-size-adjust: auto; background-colo=
r: rgba(255, 255, 255, 0);">&nbsp; &nbsp; &nbsp;bool&nbsp;</span></font><sp=
an style=3D"-webkit-tap-highlight-color: rgba(26, 26, 26, 0.292969); -webki=
t-composition-fill-color: rgba(175, 192, 227, 0.230469); -webkit-compositio=
n-frame-color: rgba(77, 128, 180, 0.230469); ">uncaught_exception_at_ctor</=
span><font color=3D"#000000"><span style=3D"-webkit-text-size-adjust: auto;=
 background-color: rgba(255, 255, 255, 0);">;<br></span></font></div><div><=
font color=3D"#000000"><span style=3D"-webkit-text-size-adjust: auto; backg=
round-color: rgba(255, 255, 255, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Transac=
tion()<br></span></font></div><div><span style=3D"-webkit-tap-highlight-col=
or: rgba(26, 26, 26, 0.292969); -webkit-composition-fill-color: rgba(175, 1=
92, 227, 0.230469); -webkit-composition-frame-color: rgba(77, 128, 180, 0.2=
30469); ">&nbsp; &nbsp; &nbsp;</span><font color=3D"#000000"><span style=3D=
"-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);"=
>{</span></font></div><div><span style=3D"-webkit-tap-highlight-color: rgba=
(26, 26, 26, 0.292969); -webkit-composition-fill-color: rgba(175, 192, 227,=
 0.230469); -webkit-composition-frame-color: rgba(77, 128, 180, 0.230469); =
">&nbsp; &nbsp; &nbsp;</span><font color=3D"#000000"><span style=3D"-webkit=
-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">&nbsp;&=
nbsp;</span></font><span style=3D"-webkit-tap-highlight-color: rgba(26, 26,=
 26, 0.292969); -webkit-composition-fill-color: rgba(175, 192, 227, 0.23046=
9); -webkit-composition-frame-color: rgba(77, 128, 180, 0.230469); ">uncaug=
ht_exception_at_ctor =3D&nbsp;</span><span style=3D"-webkit-tap-highlight-c=
olor: rgba(26, 26, 26, 0.292969); -webkit-composition-fill-color: rgba(175,=
 192, 227, 0.230469); -webkit-composition-frame-color: rgba(77, 128, 180, 0=
..230469); ">uncaught_exception();</span></div><div><span style=3D"-webkit-t=
ap-highlight-color: rgba(26, 26, 26, 0.292969); -webkit-composition-fill-co=
lor: rgba(175, 192, 227, 0.230469); -webkit-composition-frame-color: rgba(7=
7, 128, 180, 0.230469); ">&nbsp; &nbsp; &nbsp;</span><font color=3D"#000000=
"><span style=3D"-webkit-text-size-adjust: auto; background-color: rgba(255=
, 255, 255, 0);">}</span></font></div><div><font color=3D"#000000"><span st=
yle=3D"-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255=
, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;~Transaction()<br></span></font></div>=
<div><font color=3D"#000000"><span style=3D"-webkit-text-size-adjust: auto;=
 background-color: rgba(255, 255, 255, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{=
 &nbsp;if (</span></font><span style=3D"-webkit-tap-highlight-color: rgba(2=
6, 26, 26, 0.292969); -webkit-composition-fill-color: rgba(175, 192, 227, 0=
..230469); -webkit-composition-frame-color: rgba(77, 128, 180, 0.230469); ">=
uncaught_exception() and not&nbsp;</span><span style=3D"-webkit-tap-highlig=
ht-color: rgba(26, 26, 26, 0.292969); -webkit-composition-fill-color: rgba(=
175, 192, 227, 0.230469); -webkit-composition-frame-color: rgba(77, 128, 18=
0, 0.230469); ">uncaught_exception_at_ctor)</span></div><div><font color=3D=
"#000000"><span style=3D"-webkit-text-size-adjust: auto; background-color: =
rgba(255, 255, 255, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;RollBack();<br></span></font></div><div><font color=3D"#000=
000"><span style=3D"-webkit-text-size-adjust: auto; background-color: rgba(=
255, 255, 255, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br=
></span></font></div><div><font color=3D"#000000"><span style=3D"-webkit-te=
xt-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Commit();<br></span=
></font></div><div><font color=3D"#000000"><span style=3D"-webkit-text-size=
-adjust: auto; background-color: rgba(255, 255, 255, 0);">&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;}<br></span></font></div><div><font color=3D"#000000"><span st=
yle=3D"-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255=
, 0);">&nbsp;&nbsp;};</span></font></div></blockquote><br><div style=3D"-we=
bkit-text-size-adjust: auto; ">I take it back. It does not work, I don't kn=
ow what was I thinking... However, if the implementation could maintain a c=
ount of the exceptions thrown but not yet handled (instead of the mere bool=
ean retrieved via uncaught_exception) we might write this:</div><div style=
=3D"-webkit-text-size-adjust: auto; "><br></div><div><div><span style=3D"-w=
ebkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">st=
ruct Transaction<br></span></div><div><span style=3D"-webkit-text-size-adju=
st: auto; background-color: rgba(255, 255, 255, 0);">&nbsp;&nbsp;{<br></spa=
n></div><div><span style=3D"-webkit-text-size-adjust: auto; background-colo=
r: rgba(255, 255, 255, 0);">&nbsp; &nbsp; &nbsp;bool&nbsp;ue_count_at_ctor;=
<br></span></div><div><span style=3D"-webkit-text-size-adjust: auto; backgr=
ound-color: rgba(255, 255, 255, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Transact=
ion()<br></span></div><div><span style=3D"-webkit-text-size-adjust: auto; b=
ackground-color: rgba(255, 255, 255, 0);">&nbsp; &nbsp; &nbsp;{</span></div=
><div><span style=3D"-webkit-text-size-adjust: auto; background-color: rgba=
(255, 255, 255, 0);">&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;</span><span style=3D"=
-webkit-tap-highlight-color: rgba(26, 26, 26, 0.296875); -webkit-compositio=
n-fill-color: rgba(175, 192, 227, 0.230469); -webkit-composition-frame-colo=
r: rgba(77, 128, 180, 0.230469); -webkit-text-size-adjust: auto; ">ue_count=
_at_ctor</span><span style=3D"-webkit-text-size-adjust: auto; background-co=
lor: rgba(255, 255, 255, 0);">&nbsp;=3D&nbsp;uncaught_exception_count();</s=
pan></div><div><span style=3D"-webkit-text-size-adjust: auto; background-co=
lor: rgba(255, 255, 255, 0);">&nbsp; &nbsp; &nbsp;}</span></div><div><span =
style=3D"-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 2=
55, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;~Transaction()<br></span></div><div>=
<span style=3D"-webkit-text-size-adjust: auto; background-color: rgba(255, =
255, 255, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;if (</span><span style=
=3D"-webkit-tap-highlight-color: rgba(26, 26, 26, 0.292969); -webkit-compos=
ition-fill-color: rgba(175, 192, 227, 0.230469); -webkit-composition-frame-=
color: rgba(77, 128, 180, 0.230469); -webkit-text-size-adjust: auto; ">ue_c=
ount_at_ctor &lt;&nbsp;</span><span style=3D"background-color: rgba(255, 25=
5, 255, 0); -webkit-text-size-adjust: auto; ">uncaught_exception_count()</s=
pan><span style=3D"background-color: rgba(255, 255, 255, 0); -webkit-text-s=
ize-adjust: auto; ">)</span></div><div><span style=3D"-webkit-text-size-adj=
ust: auto; background-color: rgba(255, 255, 255, 0);">&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RollBack();<br></span></div><d=
iv><span style=3D"-webkit-text-size-adjust: auto; background-color: rgba(25=
5, 255, 255, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br><=
/span></div><div><span style=3D"-webkit-text-size-adjust: auto; background-=
color: rgba(255, 255, 255, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;Commit();<br></span></div><div><span style=3D"-webki=
t-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0);">&nbsp;=
&nbsp;&nbsp;&nbsp;&nbsp;}<br></span></div><div><span style=3D"-webkit-text-=
size-adjust: auto; background-color: rgba(255, 255, 255, 0);">&nbsp;&nbsp;}=
;</span></div></div><div><span style=3D"-webkit-text-size-adjust: auto; bac=
kground-color: rgba(255, 255, 255, 0);"><br></span></div><div><span style=
=3D"-webkit-text-size-adjust: auto; background-color: rgba(255, 255, 255, 0=
);">I believe&nbsp;</span><span style=3D"-webkit-tap-highlight-color: rgba(=
26, 26, 26, 0.292969); -webkit-composition-fill-color: rgba(175, 192, 227, =
0.230469); -webkit-composition-frame-color: rgba(77, 128, 180, 0.230469); b=
ackground-color: rgba(255, 255, 255, 0); -webkit-text-size-adjust: auto; ">=
uncaught_exception_count() could be implementable without significant added=
 cost: just increment a per-thread counter upon throw and decrement it upon=
 entering a handler. Is this approach worth considering?</span></div><div><=
span style=3D"-webkit-tap-highlight-color: rgba(26, 26, 26, 0.292969); -web=
kit-composition-fill-color: rgba(175, 192, 227, 0.230469); -webkit-composit=
ion-frame-color: rgba(77, 128, 180, 0.230469); background-color: rgba(255, =
255, 255, 0); -webkit-text-size-adjust: auto; "><br></span></div><div><span=
 style=3D"-webkit-tap-highlight-color: rgba(26, 26, 26, 0.292969); -webkit-=
composition-fill-color: rgba(175, 192, 227, 0.230469); -webkit-composition-=
frame-color: rgba(77, 128, 180, 0.230469); background-color: rgba(255, 255,=
 255, 0); -webkit-text-size-adjust: auto; ">Ganesh&nbsp;</span></div></body=
></html>

<p></p>

-- <br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />

--Apple-Mail-DB529632-9CF1-4D5A-942D-2829D3CCF625--

.


Author: simon.sasburg@gmail.com
Date: Sun, 23 Dec 2012 10:36:17 -0800 (PST)
Raw View
------=_Part_966_26295087.1356287777798
Content-Type: text/plain; charset=ISO-8859-1

>believe uncaught_exception_count() could be implementable without
significant added cost: just increment a per-thread counter upon throw and
decrement it upon entering a handler. Is this approach worth considering?
Actually most compilers already maintain this count internally. This is
used by https://github.com/panaseleus/stack_unwinding to  implement
something like UnwindDetector (in a currently nonstandard way).

In https://github.com/panaseleus/stack_unwinding/blob/master/boost/exception/uncaught_exception_count.hpp
you can see how uncaught_exception_count is implemented for msvc/gcc/clang.
This depends on internal compiler data-structures and such, but maybe it
should not be that difficult to standardize this into something like
std::uncaught_exception_count?

(Not this isn't my work, i just found it on the boost mailing list once and
thought it would be relevant here)

--




------=_Part_966_26295087.1356287777798
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

<span style=3D"background-color: rgba(255, 255, 255, 0);">&gt;believe&nbsp;=
</span><span style=3D"background-color: rgba(255, 255, 255, 0);">uncaught_e=
xception_<wbr>count() could be implementable without significant added cost=
: just increment a per-thread counter upon throw and decrement it upon ente=
ring a handler. Is this approach worth considering?</span><div>Actually mos=
t compilers already maintain this count internally. This is used by&nbsp;ht=
tps://github.com/panaseleus/stack_unwinding to&nbsp;&nbsp;implement somethi=
ng like&nbsp;<span style=3D"color: rgb(80, 0, 80);">UnwindDetector</span><s=
pan style=3D"color: rgb(80, 0, 80);">&nbsp;(in a currently nonstandard way)=
..</span></div><div><span style=3D"color: rgb(80, 0, 80);"><br></span></div>=
<div><span style=3D"color: rgb(80, 0, 80);">In h</span>ttps://github.com/pa=
naseleus/stack_unwinding/blob/master/boost/exception/uncaught_exception_cou=
nt.hpp you can see how&nbsp;uncaught_exception_count&nbsp;is implemented fo=
r msvc/gcc/clang. This depends on internal compiler data-structures and suc=
h, but maybe it should not be that difficult to standardize this into somet=
hing like std::uncaught_exception_count?</div><div><br></div><div>(Not this=
 isn't my work, i just found it on the boost mailing list once and thought =
it would be relevant here)</div>

<p></p>

-- <br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_966_26295087.1356287777798--

.


Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Wed, 26 Dec 2012 06:25:24 -0800 (PST)
Raw View
------=_Part_270_5133223.1356531924919
Content-Type: text/plain; charset=ISO-8859-1

On Monday, December 10, 2012 8:32:40 PM UTC+4, Jens Maurer wrote:
>
>
> Here's a proposal to offer a core feature where std::uncaught_exception()
> fails.
> Also available at
> http://jmaurer.awardspace.info/wg21/destructor-unwinding.html .
>

I don't see any reasons why a class should be responsible for partial
handling of unrelated exceptions in block scopes. In general, only a user
of a class can decide what to do when an automatic variable goes out of its
scope due to a particular circumstance. So, I believe that a user (not a
class developer) should have simple and convenient mechanism to handle
scope leaving. Such a mechanism is already invented in D.

For example, if we want to call 'commit' when control leaves a particular
scope "normally" (not due to an exception), we could write:

    struct Transaction
    {
        Transaction();
        Transcation(Transaction &&x) noexcept :
            /*...*/
        {
            x.committed = true;
        }
        void commit()
        {
            /*...*/
            committed = true;
        }
        void roll_back() noexcept;

        ~Transaction()
        {
            if (!committed)
                roll_back();
        }

        bool committed = false;
        /*...*/
    };

    void f()
    {
        Transaction transaction;
        scope_success { transaction.commit(); }
        /*...*/
    }

In some other scope evaluation of every return statement might be
interpreted as failure (as well as throwing an exception), so we could
write:

    void g()
    {
        Transaction transaction;
        /*...*/
        transaction.commit();
    }

In both cases we have simple clear self-documenting code.

--




------=_Part_270_5133223.1356531924919
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

On Monday, December 10, 2012 8:32:40 PM UTC+4, Jens Maurer wrote:<blockquot=
e class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: =
1px #ccc solid;padding-left: 1ex;">
<br>Here's a proposal to offer a core feature where std::uncaught_exception=
() fails.
<br>Also available at <a href=3D"http://jmaurer.awardspace.info/wg21/destru=
ctor-unwinding.html" target=3D"_blank">http://jmaurer.awardspace.<wbr>info/=
wg21/destructor-<wbr>unwinding.html</a> .
<br></blockquote><div>&nbsp;<br>I don't see any reasons why a class should =
be responsible for partial handling of unrelated exceptions in block scopes=
.. In general, only a user of a class can decide what to do when an automati=
c variable goes out of its scope due to a particular circumstance. So, I be=
lieve that a user (not a class developer) should have simple and convenient=
 mechanism to handle scope leaving. Such a mechanism is already invented in=
 D.<br><br>For example, if we want to call 'commit' when control leaves a p=
articular scope "normally" (not due to an exception), we could write:<br><b=
r>&nbsp;&nbsp;&nbsp; struct Transaction<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Transaction();<br>&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp; Transcation(Transaction &amp;&amp;x) noexcept :<br>&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*...*/<br>=
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x.committed =3D true;<br>&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp; void commit()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*...*/<br>&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; committed=
 =3D true;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void roll_back() noexcept;<br><br>&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ~Transaction()<br>&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp; if (!committed)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; roll_back();<br>&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; bool committed =3D false;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp; /*...*/<br>&nbsp;&nbsp;&nbsp; };<br><br>&nbsp;&nbsp;&nbsp; void f()=
<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Tran=
saction transaction;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; scope_su=
ccess { transaction.commit(); }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p; /*...*/<br>&nbsp;&nbsp;&nbsp; }<br><br>In some other scope evaluation of=
 every return statement might be interpreted as failure (as well as throwin=
g an exception), so we could write:<br><br>&nbsp;&nbsp;&nbsp; void g()<br>&=
nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Transacti=
on transaction;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*...*/<br>&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; transaction.commit();<br>&nbsp;&nb=
sp;&nbsp; }<br><br>In both cases we have simple clear self-documenting code=
..<br></div>

<p></p>

-- <br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_270_5133223.1356531924919--

.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Wed, 26 Dec 2012 22:11:44 +0100
Raw View
On 12/26/2012 03:25 PM, Nikolay Ivchenkov wrote:
> On Monday, December 10, 2012 8:32:40 PM UTC+4, Jens Maurer wrote:
>
>
>     Here's a proposal to offer a core feature where std::uncaught_exception() fails.
>     Also available at http://jmaurer.awardspace.info/wg21/destructor-unwinding.html <http://jmaurer.awardspace.info/wg21/destructor-unwinding.html> .
>
>
>  In general, only a
> user of a class can decide what to do when an automatic variable goes
> out of its scope due to a particular circumstance.

Well, right now the class decides: The destructor is called, and the user
has no further influence on that.

>  So, I believe that
> a user (not a class developer) should have simple and convenient
> mechanism to handle scope leaving. Such a mechanism is already
> invented in D.
>
> For example, if we want to call 'commit' when control leaves a
> particular scope "normally" (not due to an exception), we could
> write:

That's the way we would write a Transaction class in C++11, and
force the user to call "commit()" explicitly on each "success" scope
exit.

Unless a D-like "scope_success" facility were available:

>     void f()
>     {
>         Transaction transaction;
>         scope_success { transaction.commit(); }
>         /*...*/
>     }

My proposal would make it possible to write such a scope_success
class, taking a lambda, if it were your preferred programming
style.  Personally, I'd like to tie initialization of the transaction
and success / failure together inside the class, and not require
the user to remember whether rollback() was called roll_back().

> In both cases we have simple clear self-documenting code.

Well, the rollback is implicit in both cases.  We seem to ask the
question whether the "commit" should be explicitly stated by the
user or implied by a non-exceptional return.  I can see uses for
both ways, but the "implied" option doesn't exist in C++11.

Jens

--




.


Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Thu, 27 Dec 2012 13:56:44 -0800 (PST)
Raw View
------=_Part_229_15592896.1356645404075
Content-Type: text/plain; charset=ISO-8859-1

On Thursday, December 27, 2012 1:11:44 AM UTC+4, Jens Maurer wrote:
>
>
> Well, right now the class decides: The destructor is called, and the user
> has no further influence on that.


If I want to prevent execution of a destructor, I'm free to create objects
manually via new-expressions. In the vast majority of cases automatic
destructor calls are desirable.


> >     void f()
> >     {
> >         Transaction transaction;
> >         scope_success { transaction.commit(); }
> >         /*...*/
> >     }
>
> My proposal would make it possible to write such a scope_success
> class, taking a lambda, if it were your preferred programming
> style.


I already use such classes:

    struct scope_failure : runtime_error
    {
        char const *what() const noexcept override
        {
            return "Conditional scope statement is reached during stack
unwinding";
        }
        char const *exception_name() const noexcept override
        {
            return "::nstdx::scope_failure";
        }
    };

    template <class F>
        class scope_success_wrapper
    {
    public:
        scope_success_wrapper(F &&f) :
            m_f(NSTDX_FWD(f))
        {
            if (std::uncaught_exception())
            {
                throw scope_failure();
            }
        }
        ~scope_success_wrapper() noexcept(false)
        {
            if (!std::uncaught_exception())
                m_f();
        }
    private:
        F m_f;
    };

    struct scope_success_wrapper_maker {};

    template <class F>
        scope_success_wrapper<F> operator <<(scope_success_wrapper_maker, F
&&f)
            { return NSTDX_FWD(f); }

    #define
NSTDX_SCOPE_SUCCESS(...)
\
        auto NSTDX_CONCAT(NSTDX_NSTDX_SCOPE_SUCCESS_VAR_, __LINE__)
=                   \
            ::nstdx::scope_success_wrapper_maker() << [__VA_ARGS__]() ->
void

    void example()
    {
        Transaction t;
        NSTDX_SCOPE_SUCCESS(&) { t.commit(); }
        /*...*/
    }

Although during stack unwinding execution of blocks with
NSTDX_SCOPE_SUCCESS would always fail, this is mostly theoretical issue,
because usually (almost always?) destructors don't have such a complex
logic inside. In oder to make this technique theoretically perfect (not
considering potential performance penalties), it would be sufficient to use
(currently non-existing) function std::uncaught_exception_count that would
return number of currently active exceptions.

Well, the rollback is implicit in both cases.


Calling rollback seems to be a safe default behavior.

 We seem to ask the
> question whether the "commit" should be explicitly stated by the
> user or implied by a non-exceptional return.


Objects may have static or thread storage duration, Does it make sense to
consider invocation of their destructors as a result of a successful
execution? And is it safe (functions like "commit" may throw exceptions)?

--




------=_Part_229_15592896.1356645404075
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

On Thursday, December 27, 2012 1:11:44 AM UTC+4, Jens Maurer wrote:<blockqu=
ote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left=
: 1px #ccc solid;padding-left: 1ex;"><br>Well, right now the class decides:=
 The destructor is called, and the user
<br>has no further influence on that.</blockquote><div><br>If I want to=20
prevent execution of a destructor, I'm free to create objects manually=20
via new-expressions. In the vast majority of cases automatic destructor=20
calls are desirable.<br></div><div>&nbsp;<br></div><blockquote class=3D"gma=
il_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid=
;padding-left: 1ex;">&gt; &nbsp; &nbsp; void f()
<br>&gt; &nbsp; &nbsp; {
<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; Transaction transaction;
<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; scope_success { transaction.commit(); =
}
<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; /*...*/
<br>&gt; &nbsp; &nbsp; }
<br>
<br>My proposal would make it possible to write such a scope_success
<br>class, taking a lambda, if it were your preferred programming
<br>style.</blockquote><br>I already use such classes:<br><br>&nbsp;&nbsp;&=
nbsp; struct scope_failure : runtime_error<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char const *what() const noexcept ove=
rride<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return "Conditional scope =
statement is reached during stack unwinding";<br>&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char const=
 *exception_name() const noexcept override<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; return "::nstdx::scope_failure";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; };<br><br>&nbsp;&nbsp;&nbsp; templat=
e &lt;class F&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class scope=
_success_wrapper<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; public:<br>&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; scope_success_wrapper(F &amp;&amp=
;f) :<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=
 m_f(NSTDX_FWD(f))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (std::unca=
ught_exception())<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw scope_failure();<br>&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ~s=
cope_success_wrapper() noexcept(false)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp; if (!std::uncaught_exception())<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_f();<br>&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; private:<br>&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; F m_f;<br>&nbsp;&nbsp;&nbsp; };<br>=
<br>&nbsp;&nbsp;&nbsp; struct scope_success_wrapper_maker {};<br><br>&nbsp;=
&nbsp;&nbsp; template &lt;class F&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp; scope_success_wrapper&lt;F&gt; operator &lt;&lt;(scope_success_wra=
pper_maker, F &amp;&amp;f)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp; { return NSTDX_FWD(f); }<br><br>&nbsp;&nbsp;&nbsp; #d=
efine NSTDX_SCOPE_SUCCESS(...)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp; auto NSTDX_CONCAT(NSTDX_NSTDX_SCOPE_SUCCESS_VAR_, __LINE__) =3D&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp; ::nstdx::scope_success_wrapper_maker() &lt;&lt=
; [__VA_ARGS__]() -&gt; void<br><br>&nbsp;&nbsp;&nbsp; void example()<br>&n=
bsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Transactio=
n t;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NSTDX_SCOPE_SUCCESS(&amp=
;) { t.commit(); }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*...*/<br=
>&nbsp;&nbsp;&nbsp; }<br><br>Although
 during stack unwinding execution of blocks with NSTDX_SCOPE_SUCCESS=20
would always fail, this is mostly theoretical issue, because usually (almos=
t always?)=20
destructors don't have such a complex logic inside. In oder to make this
 technique theoretically perfect (not considering potential performance=20
penalties), it would be sufficient to use (currently non-existing)=20
function std::uncaught_exception_count that would return number of=20
currently active exceptions.<br><br><blockquote class=3D"gmail_quote" style=
=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: =
1ex;">Well, the rollback is implicit in both cases.</blockquote><div><br>Ca=
lling rollback seems to be a safe default behavior.<br><br></div><blockquot=
e class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: =
1px #ccc solid;padding-left: 1ex;"> &nbsp;We seem to ask the
<br>question whether the "commit" should be explicitly stated by the
<br>user or implied by a non-exceptional return.</blockquote><div><br>Objec=
ts may have static or thread storage duration, Does it make sense to consid=
er invocation of their destructors as a result of a successful execution? A=
nd is it safe (functions like "commit" may throw exceptions)?<br></div>

<p></p>

-- <br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_229_15592896.1356645404075--

.


Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Fri, 28 Dec 2012 01:30:20 -0800 (PST)
Raw View
------=_Part_69_4066325.1356687020143
Content-Type: text/plain; charset=ISO-8859-1

On Thursday, December 27, 2012 1:11:44 AM UTC+4, Jens Maurer wrote:
>
>
> Well, right now the class decides: The destructor is called, and the user
> has no further influence on that.
>

If I want to prevent execution of a destructor, I'm free to create objects
manually via new-expressions. In the vast majority of cases automatic
destructor calls are desirable.


> >     void f()
> >     {
> >         Transaction transaction;
> >         scope_success { transaction.commit(); }
> >         /*...*/
> >     }
>
> My proposal would make it possible to write such a scope_success
> class, taking a lambda, if it were your preferred programming
> style.


I already use such classes:

    namespace nstdx
    {
        struct scope_failure : runtime_error
        {
            char const *what() const noexcept override
            {
                return "Conditional scope-statement is reached during stack
unwinding";
            }
            char const *exception_name() const noexcept override
            {
                return "::nstdx::scope_failure";
            }
        };

        template <class F>
            class scope_success_wrapper
        {
        public:
            scope_success_wrapper(F &&f) :
                m_f(NSTDX_FWD(f))
            {
                if (std::uncaught_exception())
                {
                    throw scope_failure();
                }
            }
            ~scope_success_wrapper() noexcept(false)
            {
                if (!std::uncaught_exception())
                    m_f();
            }
            scope_success_wrapper(scope_success_wrapper const &) = delete;
        private:
            F m_f;
        };

        struct scope_success_wrapper_maker {};

        template <class F>
            scope_success_wrapper<F> operator
<<(scope_success_wrapper_maker, F &&f)
                { return {NSTDX_FWD(f)}; }
    }

    #define
NSTDX_SCOPE_SUCCESS(...)
\
        auto &&NSTDX_CONCAT(NSTDX_NSTDX_SCOPE_SUCCESS_VAR_, __LINE__)
=                 \
            ::nstdx::scope_success_wrapper_maker() << [__VA_ARGS__]() ->
void

    void example()
    {
        Transaction t;
        NSTDX_SCOPE_SUCCESS(&) { t.commit(); };
        /*...*/
    }

During stack unwinding execution of blocks with NSTDX_SCOPE_SUCCESS would
always fail. I consider this as mostly theoretical issue, because usually
(almost always?) destructors don't have such a complex logic inside. In
oder to make this technique theoretically perfect (not considering
potential performance penalties), it would be sufficient to use (currently
non-existing) function std::uncaught_exception_count that would return
number of currently active exceptions.


> Well, the rollback is implicit in both cases.


Calling rollback seems to be a safe default behavior.


> We seem to ask the
> question whether the "commit" should be explicitly stated by the
> user or implied by a non-exceptional return.
>

Objects may have static or thread storage duration, Does it make sense to
consider invocation of destructor for a thread_local variable as a result
of a successful execution? And is it safe to throw exceptions from
destructors of objects with unknown storage duration (note that functions
like "commit" may throw exceptions)?

--




------=_Part_69_4066325.1356687020143
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

On Thursday, December 27, 2012 1:11:44 AM UTC+4, Jens Maurer wrote:<blockqu=
ote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left=
: 1px #ccc solid;padding-left: 1ex;"><br>Well, right now the class decides:=
 The destructor is called, and the user
<br>has no further influence on that.
<br></blockquote><div><br>If I want to prevent execution of a destructor, I=
'm free to create objects manually via new-expressions. In the vast majorit=
y of cases automatic destructor calls are desirable.<br>&nbsp;</div><blockq=
uote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-lef=
t: 1px #ccc solid;padding-left: 1ex;">&gt; &nbsp; &nbsp; void f()
<br>&gt; &nbsp; &nbsp; {
<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; Transaction transaction;
<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; scope_success { transaction.commit(); =
}
<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; /*...*/
<br>&gt; &nbsp; &nbsp; }
<br>
<br>My proposal would make it possible to write such a scope_success
<br>class, taking a lambda, if it were your preferred programming
<br>style.</blockquote><div><br>I already use such classes:<br><br>&nbsp;&n=
bsp;&nbsp; namespace nstdx<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp; struct scope_failure : runtime_error<br>&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp; char const *what() const noexcept override<br>&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; return "Conditional scope-statement is reached during stack unwi=
nding";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =
char const *exception_name() const noexcept override<br>&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return=
 "::nstdx::scope_failure";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; };<br=
><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; template &lt;class F&gt;<br=
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class s=
cope_success_wrapper<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public:<br>&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; scope_success_wrapper(F &amp;&am=
p;f) :<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp; m_f(NSTDX_FWD(f))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (std::uncaug=
ht_exception())<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp; throw scope_failure();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ~scope_success_wrapper() noexcept(=
false)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp; if (!std::uncaught_exception())<br>&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp; m_f();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp; scope_success_wrapper(scope_success_wrapper const &am=
p;) =3D delete;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private:<br>&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; F m_f;<br=
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; };<br><br>&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp; struct scope_success_wrapper_maker {};<br><br>&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; template &lt;class F&gt;<br>&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; scope_success_wrapp=
er&lt;F&gt; operator &lt;&lt;(scope_success_wrapper_maker, F &amp;&amp;f)<b=
r>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp; { return {NSTDX_FWD(f)}; }<br>&nbsp;&nbsp;&nbsp; }<br><br=
>&nbsp;&nbsp;&nbsp; #define NSTDX_SCOPE_SUCCESS(...)&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; auto &amp;&amp;NSTDX_CONCAT(NSTDX_NSTDX_SCO=
PE_SUCCESS_VAR_, __LINE__) =3D&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ::nstdx::scope_success_wra=
pper_maker() &lt;&lt; [__VA_ARGS__]() -&gt; void<br><br>&nbsp;&nbsp;&nbsp; =
void example()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp; Transaction t;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NSTD=
X_SCOPE_SUCCESS(&amp;) { t.commit(); };<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; /*...*/<br>&nbsp;&nbsp;&nbsp; }<br><br>During stack unwinding ex=
ecution of blocks with NSTDX_SCOPE_SUCCESS would always fail. I consider th=
is as mostly theoretical issue, because usually (almost always?) destructor=
s don't have such a complex logic inside. In oder to make this technique th=
eoretically perfect (not considering potential performance penalties), it w=
ould be sufficient to use (currently non-existing) function std::uncaught_e=
xception_count that would return number of currently active exceptions.<br>=
&nbsp;</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-lef=
t: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"> Well, the rollbac=
k is implicit in both cases.</blockquote><div><br>Calling rollback seems to=
 be a safe default behavior.<br>&nbsp;</div><blockquote class=3D"gmail_quot=
e" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;paddin=
g-left: 1ex;"> We seem to ask the
<br>question whether the "commit" should be explicitly stated by the
<br>user or implied by a non-exceptional return.<br></blockquote><div><br>O=
bjects may have static or thread storage duration, Does it make sense to co=
nsider invocation of destructor for a thread_local variable as a result of =
a successful execution? And is it safe to throw exceptions from destructors=
 of objects with unknown storage duration (note that functions like "commit=
" may throw exceptions)? <br></div>

<p></p>

-- <br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_69_4066325.1356687020143--

.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Mon, 31 Dec 2012 17:57:49 +0100
Raw View
On 12/28/2012 10:30 AM, Nikolay Ivchenkov wrote:
> Objects may have static or thread storage duration, Does it make
> sense to consider invocation of destructor for a thread_local
> variable as a result of a successful execution?

I believe, yes.  (If you mean "not stack unwinding"
when talking about "successful execution".)

>  And is it safe to
> throw exceptions from destructors of objects with unknown storage
> duration (note that functions like "commit" may throw exceptions)?

It's not; throwing from a thread_local destructor calls std::terminate
(see 15.5.1p1 and 3.6.3p1).

There are other, probably more severe restrictions on static and thread
storage duration variables, for example if their construction exits
via an exception, std::terminate is called, too (3.6.2p6).

I don't think that offering the design option for block-scope
objects negatively affects static and thread storage duration uses
in a way that wasn't there before.

Jens

--




.


Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Tue, 1 Jan 2013 03:16:50 -0800 (PST)
Raw View
------=_Part_837_33000012.1357039010524
Content-Type: text/plain; charset=ISO-8859-1

On Monday, December 31, 2012 8:57:49 PM UTC+4, Jens Maurer wrote:
>
> On 12/28/2012 10:30 AM, Nikolay Ivchenkov wrote:
> > Objects may have static or thread storage duration, Does it make
> > sense to consider invocation of destructor for a thread_local
> > variable as a result of a successful execution?
>
> I believe, yes.  (If you mean "not stack unwinding"
> when talking about "successful execution".)
>

I want to understand how you define "successful execution" (as a condition
when it would be reasonable to execute operations like "commit"). I don't
consider the equivalence between "successful execution" and "not stack
unwinding" as self-evident.

>  And is it safe to
> > throw exceptions from destructors of objects with unknown storage
> > duration (note that functions like "commit" may throw exceptions)?
>
> It's not; throwing from a thread_local destructor calls std::terminate
> (see 15.5.1p1 and 3.6.3p1).
>
> There are other, probably more severe restrictions on static and thread
> storage duration variables, for example if their construction exits
> via an exception, std::terminate is called, too (3.6.2p6).
>

There are significant differences between construction and destruction with
regard to exceptions:

1) construction of a complete object always takes place when the control
enters some visible instruction in the program: variable definition,
explicit type conversion, initialization of a function parameter,
new-expression, so the exact moment of construction of a particular object
is directly visible to a programmer; destructors of objects with
non-dynamic storage duration are called implicitly and such implicit calls
have more chances to be forgotten;

2) exceptions thrown from constructors of local variables with static or
thread stroage duration can be handled; we can't surround destruction of
such objects by any try-blocks.

IMO, throwing destructors are much more error-prone than throwing
constructors.

--




------=_Part_837_33000012.1357039010524
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

On Monday, December 31, 2012 8:57:49 PM UTC+4, Jens Maurer wrote:<blockquot=
e class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: =
1px #ccc solid;padding-left: 1ex;">On 12/28/2012 10:30 AM, Nikolay Ivchenko=
v wrote:
<br>&gt; Objects may have static or thread storage duration, Does it make
<br>&gt; sense to consider invocation of destructor for a thread_local
<br>&gt; variable as a result of a successful execution?
<br>
<br>I believe, yes. &nbsp;(If you mean "not stack unwinding"
<br>when talking about "successful execution".)
<br></blockquote><div><br>I want to understand how you define "successful e=
xecution" (as a condition when it would be reasonable to execute operations=
 like "commit"). I don't consider the equivalence between "successful execu=
tion" and "not stack unwinding" as self-evident. <br><br></div><blockquote =
class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1p=
x #ccc solid;padding-left: 1ex;">&gt; &nbsp;And is it safe to
<br>&gt; throw exceptions from destructors of objects with unknown storage
<br>&gt; duration (note that functions like "commit" may throw exceptions)?
<br>
<br>It's not; throwing from a thread_local destructor calls std::terminate
<br>(see 15.5.1p1 and 3.6.3p1).
<br>
<br>There are other, probably more severe restrictions on static and thread
<br>storage duration variables, for example if their construction exits
<br>via an exception, std::terminate is called, too (3.6.2p6).
<br></blockquote><div><br>There are significant differences between constru=
ction and destruction with regard to exceptions:<br><br>1) construction of =
a complete object always takes place when the control enters some visible i=
nstruction in the program: variable definition, explicit type conversion, i=
nitialization of a function parameter,  new-expression, so the exact moment=
 of construction of a particular object is directly visible to a programmer=
; destructors of objects with non-dynamic storage duration are called impli=
citly and such implicit calls have more chances to be forgotten;<br><br>2) =
exceptions thrown from constructors of local variables with static or threa=
d stroage duration can be handled; we can't surround destruction of such ob=
jects by any try-blocks.<br><br>IMO, throwing destructors are much more err=
or-prone than throwing constructors.</div>

<p></p>

-- <br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_837_33000012.1357039010524--

.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Tue, 01 Jan 2013 21:03:33 +0100
Raw View
On 01/01/2013 12:16 PM, Nikolay Ivchenkov wrote:
> I want to understand how you define "successful execution" (as a
> condition when it would be reasonable to execute operations like
> "commit"). I don't consider the equivalence between "successful
> execution" and "not stack unwinding" as self-evident.

I don't think it's reasonable to have a static or thread storage
duration "transaction"-style object, at all, so I don't think the
question when to call "commit" arises in that context.

> There are significant differences between construction and destruction with regard to exceptions:
>
> 1) construction of a complete object always takes place when the
> control enters some visible instruction in the program: variable
> definition, explicit type conversion, initialization of a function
> parameter, new-expression, so the exact moment of construction of a
> particular object is directly visible to a programmer

I disagree.  The order of construction of non-local static or thread
storage duration objects is unspecified and often surprising to the
programmer, and there is not really any program source code corresponding
to the "exact moment of construction".

>  ; destructors of
> objects with non-dynamic storage duration are called implicitly and
> such implicit calls have more chances to be forgotten;

> 2) exceptions thrown from constructors of local variables with static
> or thread stroage duration can be handled; we can't surround
> destruction of such objects by any try-blocks.

Exceptions from constructors of non-local variables with static or
thread storage duration can't be handled.

> IMO, throwing destructors are much more error-prone than throwing constructors.

Sure.  I think the "throwing" aspect is somewhat independent of the
"commit vs. rollback" aspect; I could envision situations where a
"commit" doesn't throw an exception, either.

Jens

--




.