www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Destructor call

reply n0fun <no mail.com> writes:
import std.stdio;

struct S(alias n) {
     this(int) {
         throw new Exception("Exception");
     }
     ~this() {
         writeln("destructor " ~ n);
     }
}

void main() {
     writeln("--- 1 ---");
     try {
         auto s = S!"1"(0);
     } catch (Exception) {}
     writeln("--- 2 ---");
     try {
         auto s = new S!"2"(0);
     } catch (Exception) {}
}

Output:
--- 1 ---
--- 2 ---
destructor 2

Why the destructor is called in the second case and why not in 
the first?
How to design structs with such different behavior?
Apr 10 2018
parent reply kinke <noone nowhere.com> writes:
On Tuesday, 10 April 2018 at 18:34:54 UTC, n0fun wrote:
 Why the destructor is called in the second case and why not in 
 the first?
The first case is RAII, where destruction isn't done for not fully constructed instances. The second case is GC finalization at program shutdown and looks like a bug, as the GC should probably immediately reclaim the allocated heap memory if construction wasn't successful.
Apr 10 2018
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Tuesday, April 10, 2018 18:52:19 kinke via Digitalmars-d-learn wrote:
 On Tuesday, 10 April 2018 at 18:34:54 UTC, n0fun wrote:
 Why the destructor is called in the second case and why not in
 the first?
The first case is RAII, where destruction isn't done for not fully constructed instances.
Yeah, which is arguably a bug: https://issues.dlang.org/show_bug.cgi?id=14246
 The second case is GC finalization at program shutdown and looks
 like a bug, as the GC should probably immediately reclaim the
 allocated heap memory if construction wasn't successful.
Maybe it should reclaim the memory immediately, but I don't see how it could be argued to be a bug. When memory is freed by the GC is an implementation detail, and it's never guaranteed that a finalizer will actually ever run. - Jonathan M Davis
Apr 10 2018
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 4/10/18 3:24 PM, Jonathan M Davis wrote:
 On Tuesday, April 10, 2018 18:52:19 kinke via Digitalmars-d-learn wrote:
 On Tuesday, 10 April 2018 at 18:34:54 UTC, n0fun wrote:
 Why the destructor is called in the second case and why not in
 the first?
The first case is RAII, where destruction isn't done for not fully constructed instances.
Yeah, which is arguably a bug: https://issues.dlang.org/show_bug.cgi?id=14246
 The second case is GC finalization at program shutdown and looks
 like a bug, as the GC should probably immediately reclaim the
 allocated heap memory if construction wasn't successful.
Maybe it should reclaim the memory immediately, but I don't see how it could be argued to be a bug. When memory is freed by the GC is an implementation detail, and it's never guaranteed that a finalizer will actually ever run.
Actually, it is a bug, because the destructor is going to run the finalizer on a collection cycle, and the object may be partially created. This is due to the way it's created using new: 1. a memory block is allocated 2. The typeinfo is stored in the block 3. The runtime returns the pointer to the block. 4. the compiler calls the constructor on the block. Because the typeinfo is unconditionally stored, the finalizer will run, even if it shouldn't. The issue is that the compiler is much better at calling the constructor of the struct. This means we need 2 hooks for the construction -- 1. the memory allocation, and 2. a "post construction" call. I'd hate to pass the constructor parameters to a template function rather than the compiler handle all of these messy details. -Steve
Apr 10 2018