www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - how to allocate class without gc?

reply Igor <Vladamir.I google.com> writes:
Is there any examples that shows how to properly allocate an 
object of a class type with the new allocators and then release 
it when desired?
Jan 25
next sibling parent reply Mike Parker <aldacron gmail.com> writes:
On Tuesday, 26 January 2016 at 01:09:50 UTC, Igor wrote:
 Is there any examples that shows how to properly allocate an 
 object of a class type with the new allocators and then release 
 it when desired?
Allocate a block of memory big enough to hold an instance of your class using whichever allocator you need, then instantiate a class instance with std.conv.emplace. http://p0nce.github.io/d-idioms/#Placement-new-with-emplace
Jan 25
parent reply Igor <Vladamir.I google.com> writes:
On Tuesday, 26 January 2016 at 05:11:54 UTC, Mike Parker wrote:
 On Tuesday, 26 January 2016 at 01:09:50 UTC, Igor wrote:
 Is there any examples that shows how to properly allocate an 
 object of a class type with the new allocators and then 
 release it when desired?
Allocate a block of memory big enough to hold an instance of your class using whichever allocator you need, then instantiate a class instance with std.conv.emplace. http://p0nce.github.io/d-idioms/#Placement-new-with-emplace
I created a class using this example. But my code is now failing. It seems one can't just replace new with this and expect it to work? What is happening is some fields(strings) are not retaining their value. ubyte[__traits(classInstanceSize, App)] buffer; auto app = cast(App)emplace!App(buffer[]); //auto app = new App(); Basically the comment is the original. When I finally call createWindow, it fails because the string representing the name inside App is null... Which doesn't happen when I use new. Should it work as expected(which it isn't) or do I have to also emplace all the fields and such so they are not for some reason released?
Jan 25
next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 01/25/2016 09:47 PM, Igor wrote:

 it fails because the string representing the name inside App is null...
 Which doesn't happen when I use new.
There must be something else going on. Do you see it with a simpler type?
 Should it work as expected(which it isn't)
new allocates and constructs, emplace does not allocate and construct. That shold be the only difference.
 or do I have to also emplace all the fields and such so they are not for
 some reason released?
Not at all. Ali
Jan 25
prev sibling parent reply Daniel Kozak via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
V Tue, 26 Jan 2016 05:47:42 +0000
Igor via Digitalmars-d-learn <digitalmars-d-learn puremagic.com>
napsáno:

 On Tuesday, 26 January 2016 at 05:11:54 UTC, Mike Parker wrote:
 On Tuesday, 26 January 2016 at 01:09:50 UTC, Igor wrote:  
 Is there any examples that shows how to properly allocate an 
 object of a class type with the new allocators and then 
 release it when desired?  
Allocate a block of memory big enough to hold an instance of your class using whichever allocator you need, then instantiate a class instance with std.conv.emplace. http://p0nce.github.io/d-idioms/#Placement-new-with-emplace
I created a class using this example. But my code is now failing. It seems one can't just replace new with this and expect it to work? What is happening is some fields(strings) are not retaining their value. ubyte[__traits(classInstanceSize, App)] buffer; auto app = cast(App)emplace!App(buffer[]); //auto app = new App(); Basically the comment is the original. When I finally call createWindow, it fails because the string representing the name inside App is null... Which doesn't happen when I use new. Should it work as expected(which it isn't) or do I have to also emplace all the fields and such so they are not for some reason released?
Can you try it with GC.disable()?
Jan 26
next sibling parent Igor <Vladamir.I google.com> writes:
On Tuesday, 26 January 2016 at 09:32:06 UTC, Daniel Kozak wrote:
 V Tue, 26 Jan 2016 05:47:42 +0000
 Igor via Digitalmars-d-learn <digitalmars-d-learn puremagic.com>
 napsáno:

 [...]
Can you try it with GC.disable()?
Didn't change anything.
Jan 26
prev sibling parent reply Igor <Vladamir.I google.com> writes:
On Tuesday, 26 January 2016 at 09:32:06 UTC, Daniel Kozak wrote:
 V Tue, 26 Jan 2016 05:47:42 +0000
 Igor via Digitalmars-d-learn <digitalmars-d-learn puremagic.com>
 napsáno:

 On Tuesday, 26 January 2016 at 05:11:54 UTC, Mike Parker wrote:
 [...]
Can you try it with GC.disable()?
//ubyte[__traits(classInstanceSize, App)] buffer; auto buffer = core.stdc.stdlib.malloc(__traits(classInstanceSize, App))[0..__traits(classInstanceSize, App)]; works, so it is the ubyte line.
Jan 26
next sibling parent Daniel Kozak via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
V Tue, 26 Jan 2016 13:56:39 +0000
Igor via Digitalmars-d-learn <digitalmars-d-learn puremagic.com>
napsáno:

 On Tuesday, 26 January 2016 at 09:32:06 UTC, Daniel Kozak wrote:
 V Tue, 26 Jan 2016 05:47:42 +0000
 Igor via Digitalmars-d-learn <digitalmars-d-learn puremagic.com>
 napsáno:
  
 On Tuesday, 26 January 2016 at 05:11:54 UTC, Mike Parker wrote:  
 [...]  
Can you try it with GC.disable()?
//ubyte[__traits(classInstanceSize, App)] buffer; auto buffer = core.stdc.stdlib.malloc(__traits(classInstanceSize, App))[0..__traits(classInstanceSize, App)]; works, so it is the ubyte line.
What about: auto buffer = new ubyte[__traits(classInstanceSize, App)];
Jan 26
prev sibling next sibling parent Marc =?UTF-8?B?U2Now7x0eg==?= <schuetzm gmx.net> writes:
On Tuesday, 26 January 2016 at 13:56:39 UTC, Igor wrote:
 //ubyte[__traits(classInstanceSize, App)] buffer;
 auto buffer = 
 core.stdc.stdlib.malloc(__traits(classInstanceSize, 
 App))[0..__traits(classInstanceSize, App)];

 works, so it is the ubyte line.
 		
Can you please post the full code? From your description, it looks like the stack frame might get invalidated...
Jan 26
prev sibling parent Guillaume Piolat <contact gam3sfrommars.fr> writes:
On Tuesday, 26 January 2016 at 13:56:39 UTC, Igor wrote:
 //ubyte[__traits(classInstanceSize, App)] buffer;
 auto buffer = 
 core.stdc.stdlib.malloc(__traits(classInstanceSize, 
 App))[0..__traits(classInstanceSize, App)];

 works, so it is the ubyte line.
 		
Make sure the buffer outlives the class instance. If you emplace on the stack, then at the end of the scope your instance is gone.
Jan 26
prev sibling next sibling parent Adrian Matoga <dlang.spam matoga.info> writes:
On Tuesday, 26 January 2016 at 01:09:50 UTC, Igor wrote:
 Is there any examples that shows how to properly allocate an 
 object of a class type with the new allocators and then release 
 it when desired?
There's an example of class object allocation in the std.experimental.allocator docs: // Dynamically allocate a class object static class Customer { uint id = uint.max; this() {} this(uint id) { this.id = id; } // ... } Customer cust = theAllocator.make!Customer; assert(cust.id == uint.max); // default initialized cust = theAllocator.make!Customer(42); assert(cust.id == 42); To release the object (call the destructor and free the memory), call dispose(): theAllocator.dispose(cust); You'll need to replace "theAllocator" with the allocator you want.
Jan 26
prev sibling next sibling parent Mike <none none.com> writes:
On Tuesday, 26 January 2016 at 01:09:50 UTC, Igor wrote:
 Is there any examples that shows how to properly allocate an 
 object of a class type with the new allocators and then release 
 it when desired?
There are a number of different patterns discussed and illustrated with examples at http://wiki.dlang.org/Memory_Management. These don't use std.experimental.allocator, but should serve as a pretty good foundation for doing so. Mike
Jan 26
prev sibling parent reply Basile B. <b2.temp gmx.com> writes:
On Tuesday, 26 January 2016 at 01:09:50 UTC, Igor wrote:
 Is there any examples that shows how to properly allocate an 
 object of a class type with the new allocators and then release 
 it when desired?
This is more or less the same answer as you've get previously except that I don't use emplace but rather a copy of what's done in _d_new_class() from the D runtime: CT construct(CT, A...)(A a) trusted nogc if (is(CT == class)) { import std.experimental.allocator.mallocator; auto size = typeid(CT).init.length; auto memory = Mallocator.instance.allocate(size); // D runtime use GC here memory[0 .. size] = typeid(CT).init[]; static if (__traits(hasMember, CT, "__ctor")) (cast(CT) (memory.ptr)).__ctor(a); import core.memory: GC; GC.addRange(memory.ptr, size, typeid(CT)); return cast(CT) memory.ptr; } the GC stuff could look superfluous but without this and if there's a GC allocated members in your class (even a simple dynamic array) then you'll encounter random errors at run-time.
Jan 26
parent reply Igor <Vladamir.I google.com> writes:
On Wednesday, 27 January 2016 at 06:40:00 UTC, Basile B. wrote:
 On Tuesday, 26 January 2016 at 01:09:50 UTC, Igor wrote:
 Is there any examples that shows how to properly allocate an 
 object of a class type with the new allocators and then 
 release it when desired?
This is more or less the same answer as you've get previously except that I don't use emplace but rather a copy of what's done in _d_new_class() from the D runtime: CT construct(CT, A...)(A a) trusted nogc if (is(CT == class)) { import std.experimental.allocator.mallocator; auto size = typeid(CT).init.length; auto memory = Mallocator.instance.allocate(size); // D runtime use GC here memory[0 .. size] = typeid(CT).init[]; static if (__traits(hasMember, CT, "__ctor")) (cast(CT) (memory.ptr)).__ctor(a); import core.memory: GC; GC.addRange(memory.ptr, size, typeid(CT)); return cast(CT) memory.ptr; } the GC stuff could look superfluous but without this and if there's a GC allocated members in your class (even a simple dynamic array) then you'll encounter random errors at run-time.
Thanks. But doesn't this ultimately defeat the purpose of having manual memory management if one has to add it to the GC to be scanned? Seems like it is just an extra step. The whole point is to prevent the GC from having to mess with the object in the first place. I understand if it uses GC based objects then the GC needs to be informed but this really feels like it defeats the purpose. Ultimately I want no GC dependency. Is there an article that shows how this can be done?
Jan 27
next sibling parent Kagamin <spam here.lot> writes:
On Wednesday, 27 January 2016 at 22:39:54 UTC, Igor wrote:
 Ultimately I want no GC dependency. Is there an article that 
 shows how this can be done?
You can link with gcstub https://github.com/D-Programming-Language/druntime/blob/master/src/gcstub/gc.d it will replace GC completely.
Jan 28
prev sibling parent Basile B. <b2.temp gmx.com> writes:
On Wednesday, 27 January 2016 at 22:39:54 UTC, Igor wrote:
 But doesn't this ultimately defeat the purpose of having manual 
 memory management if one has to add it to the GC to be scanned?
You can make the LOC related to the GC optional with an additional bool template parameter and a static if, but as said previously it can introduce bugs. AddRange() is used to make the GC scan pointers inside the range (build-in array for example)) but the range is itself well manually managed.
Jan 28