digitalmars.D.learn - How to call destructor before free without dropping nogc?
- Bienlein (33/33) Aug 19 2021 Hello,
- Bienlein (7/41) Aug 19 2021 Oops, I just realized that you can also not call emplace when
- vit (58/109) Aug 19 2021 Try this:
- Bienlein (11/11) Aug 19 2021 This works, vit. Thanks! I thought it wouldn't, because your code
- evilrat (30/36) Aug 19 2021 you are probably doing something wrong, could you try @nogc ctor?
- Tejas (10/49) Aug 19 2021 Allocating to a function local variable via ```new``` always
- Ferhat =?UTF-8?B?S3VydHVsbXXFnw==?= (3/7) Aug 19 2021 I just wanted to leave this here.
- evilrat (10/19) Aug 19 2021 This is cool, but even in unit tests for malloc wrapper there is
- Ferhat =?UTF-8?B?S3VydHVsbXXFnw==?= (11/20) Aug 19 2021 If you examine the entire library, there are various use cases of
- Ferhat =?UTF-8?B?S3VydHVsbXXFnw==?= (26/27) Aug 19 2021 Btw, based on
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
Aug 19 2021
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, BienleinOops, 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.
Aug 19 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: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; } (); } }); } } } ```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, BienleinOops, 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.
Aug 19 2021
This works, vit. Thanks! I thought it wouldn't, because your code still makes use of embrace. But it somehow worked, although I don't understand why ... ;-). I also added a constructor using the same approach as your destructor and this also worked: this(int otherNum) nogc { this.num = otherNum; debug writeln("this: ", this.num); } evilrat: Will try what you suggested after work today. Too busy now.
Aug 19 2021
On Thursday, 19 August 2021 at 08:25:23 UTC, Bienlein wrote: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.you are probably doing something wrong, could you try nogc ctor? anyway nogc is way too limiting, I don't see why bother when there is already `scope` storage (should work in nogc) and -vgc flag to show possible allocations. ```d import core.lifetime; import core.stdc.stdio; import core.stdc.stdlib; class SomeClass { int a = 42; this() nogc { } this(int val) nogc { a = val; } } nogc void main() { byte[64] mem; mem.emplace!SomeClass(); printf("stack %d\n", (cast(SomeClass) mem.ptr).a); // 42 scope a = new SomeClass(); printf("scope %d\n", a.a); //42 SomeClass dynAlloc = cast(SomeClass) malloc(__traits(classInstanceSize, SomeClass)); dynAlloc = emplace!SomeClass(dynAlloc, 123); printf("dynamic %d\n", dynAlloc.a); // 123 } ```
Aug 19 2021
On Thursday, 19 August 2021 at 09:39:26 UTC, evilrat wrote:On Thursday, 19 August 2021 at 08:25:23 UTC, Bienlein wrote:Allocating to a function local variable via ```new``` always allocates on stack assuming no arguments are passed to new Read sentence 6 of https://dlang.org/spec/expression.html#new_expressions So ```d scope a = new SomeClass(); ``` actually allocates on stackOops, 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.you are probably doing something wrong, could you try nogc ctor? anyway nogc is way too limiting, I don't see why bother when there is already `scope` storage (should work in nogc) and -vgc flag to show possible allocations. ```d import core.lifetime; import core.stdc.stdio; import core.stdc.stdlib; class SomeClass { int a = 42; this() nogc { } this(int val) nogc { a = val; } } nogc void main() { byte[64] mem; mem.emplace!SomeClass(); printf("stack %d\n", (cast(SomeClass) mem.ptr).a); // 42 scope a = new SomeClass(); printf("scope %d\n", a.a); //42 SomeClass dynAlloc = cast(SomeClass) malloc(__traits(classInstanceSize, SomeClass)); dynAlloc = emplace!SomeClass(dynAlloc, 123); printf("dynamic %d\n", dynAlloc.a); // 123 } ```
Aug 19 2021
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: [...]I just wanted to leave this here. https://github.com/AuburnSounds/Dplug/blob/master/core/dplug/core/nogc.d
Aug 19 2021
On Thursday, 19 August 2021 at 15:12:03 UTC, Ferhat Kurtulmuş wrote:On Thursday, 19 August 2021 at 07:30:38 UTC, Bienlein wrote:This is cool, but even in unit tests for malloc wrapper there is only simple case with class without references to another class and no dtor. Seems like the issue is that one have to add nogc constructor/destructor overloads for emplace/destroy, and the author can't have nogc dtor because of writeln (IIRC nogc using GC is allowed with `debug` anyway), and all class members of another classes must recursively provide them as well.Hello, I allocate some instance of class C manually and then free the memory again: [...]I just wanted to leave this here. https://github.com/AuburnSounds/Dplug/blob/master/core/dplug/core/nogc.d
Aug 19 2021
On Thursday, 19 August 2021 at 15:38:19 UTC, evilrat wrote:On Thursday, 19 August 2021 at 15:12:03 UTC, Ferhat KurtulmuşThis is cool, but even in unit tests for malloc wrapper there is only simple case with class without references to another class and no dtor.If you examine the entire library, there are various use cases of nogc classes. For instance, a derived class containing references to other class objects [1]. I am not using classes heavily with D. I just once happily used dplug's nogc facilities. When I saw this thread, I just wanted to share it here.Seems like the issue is that one have to add nogc constructor/destructor overloads for emplace/destroy, and the author can't have nogc dtor because of writeln (IIRC nogc using GC is allowed with `debug` anyway), and all class members of another classes must recursively provide them as well.I agree with you. D needs more nogc facilities for OOP. It would not be so hard to include those overloads. Probably, this would violate the strictly defended safety principles of D? [1]: https://github.com/AuburnSounds/Dplug/blob/f67c14fd5ba44225d6669e87f942d641c8bf8ab8/window/dplug/window/cocoawindow.d
Aug 19 2021
On Thursday, 19 August 2021 at 15:38:19 UTC, evilrat wrote:On Thursday, 19 August 2021 at 15:12:03 UTC, Ferhat KurtulmuşBtw, based on https://github.com/dlang/druntime/blob/master/src/object.d#L4209: import core.lifetime; import core.stdc.stdio; import core.stdc.stdlib; extern (C) void rt_finalize(void *data, bool det=true) nogc nothrow; // cheap hack here alias destroy = rt_finalize; class SomeClass { int a = 42; this() nogc { } ~this() nogc {printf("nogc\n");} this(int val) nogc { a = val; } } nogc void main() { SomeClass dynAlloc = cast(SomeClass) malloc(__traits(classInstanceSize, SomeClass)); dynAlloc = emplace!SomeClass(dynAlloc, 123); printf("dynamic %d\n", dynAlloc.a); // 123 //rt_finalize(cast(void*)dynAlloc); destroy(cast(void*)dynAlloc); // cast needed :/ dunno consequences though }
Aug 19 2021