Calling destroy on struct pointer

Radu via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sat Feb 25 07:13:27 PST 2017


On Saturday, 25 February 2017 at 13:14:24 UTC, Moritz Maxeiner 
wrote:
> On Saturday, 25 February 2017 at 10:44:07 UTC, Radu wrote:
>> On Saturday, 25 February 2017 at 08:36:02 UTC, Ali Çehreli 
>> wrote:
>>> On 02/25/2017 12:17 AM, Radu wrote:
>>>
>>> > destroy(cc) -> does c = C.init
>>> > destroy(*cc); -> calls the C dtor
>>> >
>>> > Is this by design? If so - how can I destroy and get the 
>>> > dtor
>>> called
>>> > without dereferencing the pointer?
>>>
>>> It's by design because setting a pointer to null can be 
>>> considered as destroying the pointer. Dereferencing is the 
>>> right way of destroying the object through the pointer.
>>>
>>> I had added the following warning after somebody else was 
>>> burnt by this feature. :)
>>>
>>>   http://ddili.org/ders/d.en/memory.html#ix_memory.destroy
>>>
>>> Ali
>>
>> I think this is BAD. Why?
>>
>> - it is one of those WAT?? moments that brings a RTFM slap to 
>> you. The defaults should not be surprising, and in this case 
>> straight dangerous as it can lead to leaks.
>
> Unfortunately, I don't think it's viable to change destroy (see 
> below), it would probably be better to cover this in the dlang 
> tour (if it isn't already).
>
>> - it is not always possible to dereference the pointer, think 
>> some circular structures where deref would get you one of 
>> those fwd. declaration errors.
>
> In the interest of learning, could you provide an example of 
> such a case?
>
>> - the deprecated delete will call the dtor, destroy is suppose 
>> to replace delete - hence it should work the same.
>
> AFAIK destroy isn't supposed to replace delete, since delete is 
> destruction+deallocation and destroy is only destruction; and 
> by that definition they cannot work the same: AFAIR multiple 
> deletes are illegal (since that equals use after free), whereas 
> destroy can be used on the same object as often as you want 
> (the destructor will only be called the first time).
>
>>
>> In my opinion destroy should do this:
>> - call dtor if the pointer type has one defined
>> - nullify the pointer
>>
>> This is what I was expecting anyhow to happen...
>
> This change would be backwards-incompatible and breaks user 
> code, especially manual memory management:
>
> ---
> struct A {}
>
> auto a = cast (A*) malloc(A.sizeof); // Allocate
> emplace(a, 42);                      // Construct
>
> destroy(a);                          // Destruct
> free(a);                             // Deallocate
> ---
>
> if destroy were to already nullify a, how were one supposed to 
> deallocate a?

Here is sample on how destroy fails with a fwd decl error:

struct A
{
     B b;
     C c;
}

struct B
{
     Wrap!A val;
}

struct C
{
     Wrap!A val;
}

struct Wrap(T)
{

     this(bool b)
     {
         t = cast(T*) malloc(T.sizeof);
     }

     ~this()
     {
         destroy(*t);  // Error: struct app.A no size because of 
forward reference
     }
     T* t;
}

Manual management fails now with the current construct, inst't it?

auto a = cast (A*) malloc(A.sizeof); // Allocate
emplace(a, 42);                      // Construct

destroy(a);                          // Destruct
|-- here a becomes null
assert(a is null); // :}
free(a);                             // Deallocate
|- free null...

You need to save a into a temp, then call free on temp.

A nice to have enhancement would be to return the destroyed 
pointer from destroy, enabling something like:

destroy(a).free();




More information about the Digitalmars-d-learn mailing list