View mode: basic / threaded / horizontal-split · Log in · Help
April 13, 2005
Proposal: "auto" and exceptions
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
Re: Proposal: "auto" and exceptions
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
Re: Proposal:
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
Re: Proposal: "auto" and exceptions
"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
Re: Proposal:
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
Re: Proposal:
> 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
Re: Proposal:
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
Re: Proposal:
> 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
Re: Proposal:
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
Re: Proposal:
"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