How to call destructor before free without dropping @nogc?
vit
vit at vit.vit
Thu Aug 19 09:29:30 UTC 2021
On Thursday, 19 August 2021 at 08:25:23 UTC, Bienlein wrote:
> On Thursday, 19 August 2021 at 07:30:38 UTC, Bienlein wrote:
>> Hello,
>>
>> I allocate some instance of class C manually and then free the
>> memory again:
>>
>> class C {
>> int num;
>>
>> ~this() {
>> writeln("~this");
>> }
>> }
>>
>> void foo() // @nogc
>> {
>> auto mem = cast(C)malloc(__traits(classInstanceSize,
>> C));
>> auto c = emplace!(C)(mem);
>>
>> c.num = 789;
>>
>> destroy(c);
>> free(cast(void*) c);
>> c = null;
>> }
>>
>> int main()
>> {
>> foo();
>> }
>>
>> The code above works well as the destructor of c in class C is
>> called by destroy. Problem is that destroy cannot be used once
>> function foo is annotated with @nogc. There seems to be no way
>> round it.
>>
>> What I want is to keep the function foo annotated with @nogc,
>> but still have the destructor of C be called before free is
>> called. Is there a way to call the destructor through meta
>> programming or some kind of reflection so that I can create
>> some generic function that calls the destructor and then free
>> for any kind of class?
>>
>> Thanks, Bienlein
>
> Oops, I just realized that you can also not call emplace when
> @nogc is present. Well that is at least consistent with not
> either being able to call destroy ;-).
>
> So, I guess this means that you can forget about manually
> allocating and freeing some instance of a class and using @nogc
> as well. That's a pitty, @nogc was a good idea.
Try this:
```d
import std;
import core.stdc.stdlib : malloc, free;
class C {
int num;
~this() @nogc{
debug writeln("~this");
}
}
void foo() @nogc
{
auto mem = cast(C)malloc(__traits(classInstanceSize, C));
auto c = emplace!(C)(mem);
c.num = 789;
destruct(c);
free(cast(void*) c);
c = null;
}
void main()
{
foo();
}
//https://github.com/atilaneves/automem/blob/master/source/automem/utils.d
void destruct(T)(T obj) if (is(T == class)) {
(cast(_finalizeType!T) &rt_finalize)(() @trusted { return
cast(void*) obj; }());
}
private extern(C){
void rt_finalize(void* p, bool det = true) @trusted @nogc pure
nothrow;
template _finalizeType(T) {
import std.traits: Unqual;
static if (is(Unqual!T == Object)) {
alias _finalizeType = typeof(&rt_finalize);
} else {
import std.traits : BaseClassesTuple;
import std.meta : AliasSeq;
alias _finalizeType = typeof(function void(void* p,
bool det = true) {
// generate a body that calls all the destructors
in the chain,
// compiler should infer the intersection of
attributes
foreach (B; AliasSeq!(T, BaseClassesTuple!T)) {
// __dtor, i.e. B.~this
static if (__traits(hasMember, B, "__dtor"))
() { B obj; obj.__dtor; } ();
// __xdtor, i.e. dtors for all RAII members
static if (__traits(hasMember, B, "__xdtor"))
() { B obj; obj.__xdtor; } ();
}
});
}
}
}
```
More information about the Digitalmars-d-learn
mailing list