www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Is it supposed to be safe to throw inside struct destructors?

reply Marco Leise <Marco.Leise gmx.de> writes:
I would like to hear a definite answer on this. A failure in
~this() leaves the program in an undefined state. You cannot
back out of returning from a function that needs to perform
cleanup on stack structs. Constructors do not have this
problem. With scope(failure) you can guard all resources and
guarantee cleanup after an exception is thrown.

If we CAN throw in ~this(), the exception should (based on
the fact that the program is now in an invalid state, like
after a failed assertion or out-of-memory) be wrapped in
something like a FinalizeError to tear down the whole program.

If not, then error reporting needs to be done in a "nothrow"
context. This has far reaching consequences since typically
error logging means doing I/O and I/O can fail and throw
Exceptions. So either the logging calls in destructors
would be wrapped in try-catch or there needs to be some
printf() calls scattered in ~this().


References:
http://wiki.dlang.org/DIP44
http://forum.dlang.org/thread/op.vvek7te7tuzx1w cybershadow.mshome.net?page=3#post-iqjhlc:241rde:241:40digitalmars.com
http://d.puremagic.com/issues/show_bug.cgi?id=4621

-- 
Marco
Apr 07 2014
parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
07-Apr-2014 12:33, Marco Leise пишет:
 I would like to hear a definite answer on this. A failure in
 ~this() leaves the program in an undefined state. You cannot
 back out of returning from a function that needs to perform
 cleanup on stack structs. Constructors do not have this
 problem. With scope(failure) you can guard all resources and
 guarantee cleanup after an exception is thrown.
There is exception chaining for that. All collateral exceptions get appended to a list. IIRC throw in a destructor while exception is in flight breaks out of this particular destructor, other if any are then executed in turn.
 If we CAN throw in ~this(), the exception should (based on
 the fact that the program is now in an invalid state, like
 after a failed assertion or out-of-memory) be wrapped in
 something like a FinalizeError to tear down the whole program.

 If not, then error reporting needs to be done in a "nothrow"
 context. This has far reaching consequences since typically
 error logging means doing I/O and I/O can fail and throw
 Exceptions. So either the logging calls in destructors
 would be wrapped in try-catch or there needs to be some
 printf() calls scattered in ~this().


 References:
 http://wiki.dlang.org/DIP44
 http://forum.dlang.org/thread/op.vvek7te7tuzx1w cybershadow.mshome.net?page=3#post-iqjhlc:241rde:241:40digitalmars.com
 http://d.puremagic.com/issues/show_bug.cgi?id=4621
-- Dmitry Olshansky
Apr 07 2014
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Monday, 7 April 2014 at 19:19:18 UTC, Dmitry Olshansky wrote:
 07-Apr-2014 12:33, Marco Leise пишет:
 I would like to hear a definite answer on this. A failure in
 ~this() leaves the program in an undefined state. You cannot
 back out of returning from a function that needs to perform
 cleanup on stack structs. Constructors do not have this
 problem. With scope(failure) you can guard all resources and
 guarantee cleanup after an exception is thrown.
There is exception chaining for that. All collateral exceptions get appended to a list. IIRC throw in a destructor while exception is in flight breaks out of this particular destructor, other if any are then executed in turn.
That's the theory, but in practice, throwing an exception allocates, and you can't allocate if you are in a GC collect cycle. So it's kind of back to square 1 in terms of throwing in destructors: Don't do it :/
Apr 07 2014
parent Marco Leise <Marco.Leise gmx.de> writes:
Am Mon, 07 Apr 2014 21:36:34 +0000
schrieb "monarch_dodra" <monarchdodra gmail.com>:

 On Monday, 7 April 2014 at 19:19:18 UTC, Dmitry Olshansky wrote:
 07-Apr-2014 12:33, Marco Leise =D0=BF=D0=B8=D1=88=D0=B5=D1=82:
 I would like to hear a definite answer on this. A failure in
 ~this() leaves the program in an undefined state. You cannot
 back out of returning from a function that needs to perform
 cleanup on stack structs. Constructors do not have this
 problem. With scope(failure) you can guard all resources and
 guarantee cleanup after an exception is thrown.
There is exception chaining for that. All collateral exceptions=20 get appended to a list. IIRC throw in a destructor while=20 exception is in flight breaks out of this particular=20 destructor, other if any are then executed in turn.
=20 That's the theory, but in practice, throwing an exception=20 allocates, and you can't allocate if you are in a GC collect=20 cycle. =20 So it's kind of back to square 1 in terms of throwing in=20 destructors: Don't do it :/
Aye! --=20 Marco
Apr 07 2014