Problem with dtor behavior

Moritz Maxeiner via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Fri Jul 28 08:49:42 PDT 2017


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


More information about the Digitalmars-d-learn mailing list