On Friday, 28 July 2017 at 11:39:56 UTC, SrMordred wrote:
On Thursday, 27 July 2017 at 20:28:47 UTC, Moritz Maxeiner wrote:
On Thursday, 27 July 2017 at 19:19:27 UTC, SrMordred wrote:
//D-CODE
struct MyStruct{
    int id;
    this(int id){
        writeln("ctor");
    }
    ~this(){
        writeln("dtor");
    }
}

MyStruct* obj;
void push(T)(auto ref T value){
    obj[0] = value;
}

void main()
{
    obj = cast(MyStruct*)malloc( MyStruct.sizeof );
    push(MyStruct(1));
}

OUTPUT:
ctor
dtor
dtor

I didnt expected to see two dtors in D (this destroy any attempt to free resources properly on the destructor).

AFAICT it's because opAssign (`obj[0] = value` is an opAssign) creates a temporary struct object (you can see it being destroyed by printing the value of `cast(void*) &this` in the destructor).

Can someone explain why is this happening and how to achieve the same behavior as c++?

Use std.conv.emplace:

---
import std.conv : emplace;

void push(T)(auto ref T value){
        emplace(obj, value);
}
---

It worked but isnt this odd?

Here's the summary:

Because D uses default initialization opAssign assumes its destination is an initialized (live) object (in this case located at `obj[0]`) and destructs this object before copying the source over it. Emplace is designed to get around this by assuming that its destination is an uninitialized memory chunk (not a live object). `MyStruct(1)` is a struct literal, not a struct object, i.e. (in contrast to struct objects) it's never destroyed. When passing the struct literal into `push`, a new struct object is created and initialized from the struct literal; this struct object is then passed into `push` instead of the struct literal, used as the source for the opAssign, and then finally destroyed after `push` returns. When assigning the struct literal directly to `obj[0]` no such extra struct object gets created, `obj[0]` still gets destroyed by opAssign and then overwritten by the struct literal.

W.r.t to `auto ref`: To paraphrase the spec [1], an auto ref parameter is passed by reference if and only if it's an lvalue (i.e. if it has an accessible address). (Struct) literals are not lvalues (they do not have an address) and as such cannot be passed by reference.


[1] https://dlang.org/spec/template.html#auto-ref-parameters

Reply via email to