April 13, 2005
Currently, auto classes are only deterministically destroyed if execution leaves scope normally, ie. if an exception is not thrown (see example below).  To avoid one potential cause of multiple in-flight exceptions while maintaining the guarantee of deterministtic destruction, I propose that all auto objects be cleaned up by the system upon exception recovery--that is, when execution leaves the scope of a catch block normally rather than via a throw expression.  This would serve the additional purpose of allowing the programmer to create non-recoverable errors by throwing an auto object with a terminate statement in the object's dtor.

Here's an example of current behavior:

# auto class AutoClass
# {
# public:
#     this()
#     {
#         printf( "ctor\n" );
#         throw new Exception( "" );
#     }
#
#     ~this()
#     {
#         printf( "dtor\n" );
#     }
# }
#
#
# void main()
# {
#     try
#     {
#         auto AutoClass c = new AutoClass();
#     }
#     catch( Exception e )
#     {
#         printf( "caught\n" );
#     }
#     printf( "continue\n" );
# }

Prints:

ctor
caught
continue
dtor

The desired behavior would be to print:

ctor
caught
dtor
continue


April 13, 2005
Sean Kelly wrote:
> The desired behavior would be to print:
> 
> ctor
> caught
> dtor
> continue
> 
> 

Young D Soul wanting to learn speaking:

Is this Ok:

# auto class AutoClass
# {
# public:
#    this()
#    {  try
#       {  printf( "ctor\n" );
#          throw new Exception( "" );
#       }
#       catch( Exception e )
#       {  printf( "caught in ctor, calling dtor\n" );
#          delete this;
#          printf( "dtor called\n" );
#          throw new Exception( e.toString() );
#       }
#    }
#    ~this()
#    {  printf( "dtor\n" );
#    }
# }
#
# void main()
# {
#    try
#    {  auto AutoClass c = new AutoClass();
#    }
#    catch( Exception e )
#    {  printf( "caught in main\n" );
#    }
#    printf( "continue in main\n" );
# }

which prints:

ctor
caught in ctor, calling dtor
dtor
dtor called
caught in main
continue in main
April 13, 2005
In article <d3jl7f$242d$1@digitaldaemon.com>, Carlos says...
>
>Young D Soul wanting to learn speaking:
>
>Is this Ok:

Yes, though it should not be necessary to do this manually.  One slight change below as well.

># auto class AutoClass
># {
># public:
>#    this()
>#    {  try
>#       {  printf( "ctor\n" );
>#          throw new Exception( "" );
>#       }
>#       catch( Exception e )
>#       {  printf( "caught in ctor, calling dtor\n" );
>#          delete this;
>#          printf( "dtor called\n" );

throw e; // just rethrow the old exception

>#       }
>#    }
>#    ~this()
>#    {  printf( "dtor\n" );
>#    }
># }
>#
># void main()
># {
>#    try
>#    {  auto AutoClass c = new AutoClass();
>#    }
>#    catch( Exception e )
>#    {  printf( "caught in main\n" );
>#    }
>#    printf( "continue in main\n" );
># }
>
>which prints:
>
>ctor
>caught in ctor, calling dtor
>dtor
>dtor called
>caught in main
>continue in main


April 13, 2005
"Sean Kelly" <sean@f4.ca> wrote in message news:d3jhab$20b2$1@digitaldaemon.com...
> Currently, auto classes are only deterministically destroyed if execution
> leaves
> scope normally, ie. if an exception is not thrown (see example below).
[snip]

Interesting test. It could be a bug in exception handling and auto classes -
it seems odd to run the dtor after both the try and catch scopes are gone.
When I run
 auto class AutoClass {
     this() { printf( "ctor\n" ); }
     ~this() { printf( "dtor\n" ); }
     void yikes() {  throw new Exception( "" );  }
 }
 void main() {
     try {
         auto AutoClass c = new AutoClass();
         c.yikes();
     } catch( Exception e ){
         printf( "caught\n" );
     }
     printf( "continue\n" );
 }

I get

D:\d>test
ctor
dtor
caught
continue

The only difference is throwing after the ctor vs inside.


April 13, 2005
In article <d3jnpd$26hi$1@digitaldaemon.com>, Ben Hinkle says...
>
>
>"Sean Kelly" <sean@f4.ca> wrote in message news:d3jhab$20b2$1@digitaldaemon.com...
>> Currently, auto classes are only deterministically destroyed if execution
>> leaves
>> scope normally, ie. if an exception is not thrown (see example below).
>[snip]
>
>Interesting test. It could be a bug in exception handling and auto classes - it seems odd to run the dtor after both the try and catch scopes are gone. When I run
> auto class AutoClass {
>     this() { printf( "ctor\n" ); }
>     ~this() { printf( "dtor\n" ); }
>     void yikes() {  throw new Exception( "" );  }
> }
> void main() {
>     try {
>         auto AutoClass c = new AutoClass();
>         c.yikes();
>     } catch( Exception e ){
>         printf( "caught\n" );
>     }
>     printf( "continue\n" );
> }
>
>I get
>
>D:\d>test
>ctor
>dtor
>caught
>continue
>
>The only difference is throwing after the ctor vs inside.

Well that's interesting.  So the problem is only when an exception is thrown from the ctor?

Either way, I'd like to know if anyone has issues with my suggestion, as it seems a simple way to address the Irrecoverable exception idea.  Is there any reason RAII would require the auto classes to be cleaned up immediately upon scope exit rather than delaying this until catch scope exit?  This practice causes a ton of problems in C++, and it would be nice if these problems could be so neatly eliminated while addressing Matthew's request at the same time.


Sean


April 13, 2005
> Either way, I'd like to know if anyone has issues with my suggestion, as
> it
> seems a simple way to address the Irrecoverable exception idea.  Is there
> any
> reason RAII would require the auto classes to be cleaned up immediately
> upon
> scope exit rather than delaying this until catch scope exit?  This
> practice
> causes a ton of problems in C++, and it would be nice if these problems
> could be
> so neatly eliminated while addressing Matthew's request at the same time.

I think the Matthew was proposing that the program exit at the end of the top-most catch block - not the immediate catch block. For example if foo1 calls foo2 calls foo3 and all have try catches then an unrecoverable exception thrown in foo3 will execute all the catches (or finally statements) in foo3, foo2, foo1 in order and then exit. From what I understand of your proposal the prog would exit at the catch with the auto, which I guess the user would have to make sure is the top.


April 13, 2005
In article <d3k1cf$2fdg$1@digitaldaemon.com>, Ben Hinkle says...
>
>> Either way, I'd like to know if anyone has issues with my suggestion, as
>> it
>> seems a simple way to address the Irrecoverable exception idea.  Is there
>> any
>> reason RAII would require the auto classes to be cleaned up immediately
>> upon
>> scope exit rather than delaying this until catch scope exit?  This
>> practice
>> causes a ton of problems in C++, and it would be nice if these problems
>> could be
>> so neatly eliminated while addressing Matthew's request at the same time.
>
>I think the Matthew was proposing that the program exit at the end of the top-most catch block - not the immediate catch block. For example if foo1 calls foo2 calls foo3 and all have try catches then an unrecoverable exception thrown in foo3 will execute all the catches (or finally statements) in foo3, foo2, foo1 in order and then exit. From what I understand of your proposal the prog would exit at the catch with the auto, which I guess the user would have to make sure is the top.

No.  I was proposing that auto class destruction be deferred until a catch clause exits normally rather than with another throw exception.  By Matthew's terminology, that would be the top-most catch block.  ie.

# void f1() {
#     try {
#         auto Foo f = new Foo();
#         throw new Exception("");
#     catch(Exception e) {
#         throw e;
#     }
# }
#
# void f2() {
#     try {
#         auto Bar b = new Bar();
#         f1();
#     }
#     catch(Exception e) {
#         throw new Exception("");
#     }
# }
#
# void f3() {
#     try {
#         f2();
#     }
#     catch(Exception e) {}
#     // auto Foo f would be destroyed here, followed by auto Bar b
# }

The only slightly sticky issue I can think of is how do auto objects declared within one of the catch blocks fit into the destruction ordering scheme?  Should destruction be strictly LIFO or should a more complex ordering be imposed?


Sean


April 13, 2005
> No.  I was proposing that auto class destruction be deferred until a catch
> clause exits normally rather than with another throw exception.  By
> Matthew's
> terminology, that would be the top-most catch block.  ie.

Plus Matthew would require all catch blocks to rethrow automatically until the top-most block. Otherwise with the foo1, foo2, foo3 example if foo2 didn't rethrow then it would leave the catch block normally and foo1's catch wouldn't run. I understand Matthew's request as: if an instance of a certain class of objects is thrown then all catch blocks on the stack automatically rethrow if the catch block is exited normally (ie - no catch block can be exited normally).


April 13, 2005
In article <d3k73p$2k73$1@digitaldaemon.com>, Ben Hinkle says...
>
>> No.  I was proposing that auto class destruction be deferred until a catch
>> clause exits normally rather than with another throw exception.  By
>> Matthew's
>> terminology, that would be the top-most catch block.  ie.
>
>Plus Matthew would require all catch blocks to rethrow automatically until the top-most block. Otherwise with the foo1, foo2, foo3 example if foo2 didn't rethrow then it would leave the catch block normally and foo1's catch wouldn't run. I understand Matthew's request as: if an instance of a certain class of objects is thrown then all catch blocks on the stack automatically rethrow if the catch block is exited normally (ie - no catch block can be exited normally).

But the point of forcing a rethrow all the way out of main would just be to insure termination, correct?  If so, this would be handled by terminate() in the class dtor in my suggestion.  My only (growing) reservation is that I'm not entirely happy with the impact on auto objects in evaluated catch blocks, as I think they should be destroyed *after* the in-function auto objects whose destruction was deferred.  ie. I would want destruction to be delayed, but destruction order to be preserved, and this isn't strictly LIFO, which would slightly complicate implementation (and explanation).


Sean


April 14, 2005
"Ben Hinkle" <bhinkle@mathworks.com> wrote in message news:d3k1cf$2fdg$1@digitaldaemon.com...
>> Either way, I'd like to know if anyone has issues with my
>> suggestion, as it
>> seems a simple way to address the Irrecoverable exception idea.
>> Is there any
>> reason RAII would require the auto classes to be cleaned up
>> immediately upon
>> scope exit rather than delaying this until catch scope exit?
>> This practice
>> causes a ton of problems in C++, and it would be nice if these
>> problems could be
>> so neatly eliminated while addressing Matthew's request at the
>> same time.
>
> I think the Matthew was proposing that the program exit at the end of the top-most catch block - not the immediate catch block. For example if foo1 calls foo2 calls foo3 and all have try catches then an unrecoverable exception thrown in foo3 will execute all the catches (or finally statements) in foo3, foo2, foo1 in order and then exit. From what I understand of your proposal the prog would exit at the catch with the auto, which I guess the user would have to make sure is the top.

Ben describes it aright


« First   ‹ Prev
1 2
Top | Discussion index | About this forum | D home