Managing malloced memory

Steven Schveighoffer schveiguy at gmail.com
Thu Oct 7 11:55:35 UTC 2021


On 10/6/21 3:22 PM, anon wrote:
> Sorry for messed up post, fixed it.
> 
> On Wednesday, 6 October 2021 at 18:29:34 UTC, Steven Schveighoffer wrote:
>> You can return this thing and pass it around, and the GC will keep it 
>> alive until it's not needed. Then on collection, the value is freed.
> 
> Is the gc required to call ~this() on the struct? I remember it being 
> implementation defined. Probably doesn't matter for my usecase, just 
> curious.

The GC is technically not required to free any blocks ever. But in 
general, it does.

When it does free a struct, as long as you allocated with `new`, it 
should call the dtor.

>> Why is it a problem that it calls the dtor? I thought the whole point 
>> of refcounting is for the dtor to decrement the refcount, and free the 
>> malloc'd object only when the refcount has actually reached 0.
> 
> Yes I'm afraid of double freeing. How do I pass existing struct to 
> refcounted without the already existing copy calling destructed on 
> function exit.
> 

Just FYI, you should reply to the posts that you quote, or at least copy 
the "X Y wrote" line so people understand the thread. This question was 
written by H.S. Teoh, but I'll respond.

The destructor is called once per copy. This is why disabling copy 
prevents double freeing.

There are cases where the compiler avoids calling the destructor because 
the instance is moved. Such as returning a newly constructed item 
(typically referred to as an "rvalue"), or passing a newly constructed 
item into a parameter. The parameter will be destroyed, but the 
call-site constructed item will not.

e.g.:

```d
struct S
{
    int x;
    ~this() { writeln("destructor called"); }
}

void foo(S s) {

    // destructor for s called here
}

S makeS(int x)
{
    return S(x); // no destructor called here.
}

void main()
{
    foo(S(1)); // no destructor called for this rvalue
    auto s = makeS(1);
    // destructor for s called here.
    foo(makeS(1)); // only one destructor called at the end of foo
}
```

You can also use std.algorithm.move to avoid calling destructors on live 
data. However, the destructor will still be called, it just will be 
called on an S.init value.

-Steve


More information about the Digitalmars-d-learn mailing list