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