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