www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 9334] New: Dtor and postblit for struct heap object are not always called

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9334

           Summary: Dtor and postblit for struct heap object are not
                    always called
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: nobody puremagic.com
        ReportedBy: maxim maxim-fomin.ru


--- Comment #0 from Maxim Fomin <maxim maxim-fomin.ru> 2013-01-17 08:22:18 PST
---
If struct object allocated on heap is default constructed, dtor is not called.
If one has non-default initializer, dtor (and postblit) is called.

import std.stdio : writefln;

struct S
{
    int i;
    this(this) { writefln("%X postbit", i); i = 0;}
    ~this() { writefln("%X dtor", i); }
}

auto foo()
{
    S* s = new S(); // add any argument to new to call dtor
}

void main()
{
    foo();
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jan 17 2013
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9334


monarchdodra gmail.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |monarchdodra gmail.com


--- Comment #1 from monarchdodra gmail.com 2013-01-17 08:35:18 PST ---
(In reply to comment #0)
 If struct object allocated on heap is default constructed, dtor is not called.
 If one has non-default initializer, dtor (and postblit) is called.
 
 import std.stdio : writefln;
 
 struct S
 {
     int i;
     this(this) { writefln("%X postbit", i); i = 0;}
     ~this() { writefln("%X dtor", i); }
 }
 
 auto foo()
 {
     S* s = new S(); // add any argument to new to call dtor
 }
 
 void main()
 {
     foo();
 }

I don't think so: The postblit (and destructor) you are seeing comes (AFAIK) from moving a stack allocated S() into the heap, *during* the new. In both case, the object that is on the heap is never destroyed. D makes no promises that things get destroyed at the end of a run. (again, AFAIK). Check this out: //---- import std.stdio; struct S { int i; this(this) { writefln("%X postbit", i); i = 0;} ~this() { writefln("%X dtor", i); } } auto foo() { S* s = new S(5); // add any argument to new to call dtor writeln("here"); } void main() { foo(); } //---- 5 postbit 5 dtor here //---- As you can see, the dtor we are seeing is *NOT* the one that runs at the end of the program. From a performance point of view, I can question why there is a postblit and a dtor call at all, but it isn't wrong. You probably don't see it on "default construction", because the runtime only copies the T.init value (so no postblit or any of that jazz). As far as I'm concerned, there is nothing wrong here. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jan 17 2013
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9334



--- Comment #2 from Maxim Fomin <maxim maxim-fomin.ru> 2013-01-17 09:47:29 PST
---
(In reply to comment #1)
 I don't think so: The postblit (and destructor) you are seeing comes (AFAIK)
 from moving a stack allocated S() into the heap, *during* the new.

You misunderstood the point. The problem is not that D's GC does not collect structs, the problem is within foo. The code: /* to reduce phobos bloat and remove postblit*/ import core.stdc.stdio : printf; struct S { int i; ~this() { printf("%X dtor\n", i); } } auto foo() { S* s = new S(); // add any argument to new to call dtor } void main() { foo(); } Dump of assembler code for function _D4main3fooFZv: 0x0000000000418768 <+0>: push %rbp 0x0000000000418769 <+1>: mov %rsp,%rbp 0x000000000041876c <+4>: movabs $0x6362a0,%rdi 0x0000000000418776 <+14>: callq 0x41a09c <_d_newitemT> 0x000000000041877b <+19>: pop %rbp 0x000000000041877c <+20>: retq End of assembler dump. As you see there is no stack allocation. Case #2 add non-default parameter (1) Dump of assembler code for function _D4main3fooFZv: 0x0000000000418768 <+0>: push %rbp 0x0000000000418769 <+1>: mov %rsp,%rbp 0x000000000041876c <+4>: sub $0x10,%rsp 0x0000000000418770 <+8>: movabs $0x6362a0,%rdi 0x000000000041877a <+18>: callq 0x41a0c4 <_d_newitemT> 0x000000000041877f <+23>: movl $0x1,-0x8(%rbp) 0x0000000000418786 <+30>: lea -0x8(%rbp),%rsi 0x000000000041878a <+34>: mov %rax,%rdi 0x000000000041878d <+37>: movsb %ds:(%rsi),%es:(%rdi) 0x000000000041878e <+38>: movsb %ds:(%rsi),%es:(%rdi) 0x000000000041878f <+39>: movsb %ds:(%rsi),%es:(%rdi) 0x0000000000418790 <+40>: movsb %ds:(%rsi),%es:(%rdi) 0x0000000000418791 <+41>: callq 0x418798 <_D4main3fooFZv+48> 0x0000000000418796 <+46>: jmp 0x4187a2 <_D4main3fooFZv+58> 0x0000000000418798 <+48>: lea -0x8(%rbp),%rdi 0x000000000041879c <+52>: callq 0x4186f0 <_D4main1S6__dtorMFZv> 0x00000000004187a1 <+57>: retq 0x00000000004187a2 <+58>: leaveq 0x00000000004187a3 <+59>: retq End of assembler dump. Now there is S(1) (struct, not pointer - why?) which is written over memory allocated by new and dtor is called for this stack struct. Note, even if you pass 0 (which useless because i is zero anyway), dmd still emits dummy code like above except that there is 0 instead of 1. However, it need not to create a temporary S(1), just write 1 directly to value returned from new, or in other words the expected code in case #2 is: Dump of assembler code for function _D4main3fooFZv: 0x0000000000418768 <+0>: push %rbp 0x0000000000418769 <+1>: mov %rsp,%rbp 0x000000000041876c <+4>: movabs $0x6362a0,%rdi 0x0000000000418776 <+14>: callq 0x41a09c <_d_newitemT> <change allocated value>: movl $0x1, (%eax) 0x000000000041877b <+19>: pop %rbp 0x000000000041877c <+20>: retq End of assembler dump. Note, this is not about optimizing, because auto foo() { S* s = new S(1); } have no reason to create a temporary struct and than call destructor on it. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jan 17 2013