www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Allocating a class within another class during object init w/o passing

reply David Zhang <straivers98 gmail.com> writes:
Hello,

It is my understanding that a class can have a struct as one of 
its members, and it will be allocated in-line with the rest of 
the class' members. My question is this; how might I be able to 
do this with another class? I want to be able to allocate Foo 
using std.experimental.allocator without having to pass in a 
reference to the actual allocator. Thanks.

eg:
class SomeClass {}

class Foo {
     this(IAllocator alloc) {
         sc = alloc.make!SomeClass;
         this.alloc = alloc
     }

     ~this() {
         alloc.dispose(sc);
     }

     size_t something;
     SomeClass sc;
     IAllocator alloc
}

auto foo = alloc.make!Foo(alloc);

vs.

struct SomeStruct {}

class Foo {
     this() {
         ss = SomeStruct (...);
     }

     size_t something;
     SomeStruct ss;
}

auto foo = alloc.make!Foo;
Dec 15 2016
next sibling parent visitor <visitor gmail.com> writes:
On Thursday, 15 December 2016 at 17:44:23 UTC, David  Zhang wrote:
 
would something like this be a solution ? import std.stdio; import std.experimental.allocator; class SomeClass { int someint = 42; static SomeClass opCall(int a) { auto inst = theAllocator.make!SomeClass; inst.someint += a; return inst; } void destruct() { theAllocator.dispose(this); } } class Foo { this() { sc = SomeClass(7); sc.someint -= 42; } ~this() { sc.destruct(); } size_t something; SomeClass sc; } void main(string[] args) { auto foo = theAllocator.make!Foo; assert(foo.sc.someint == 7); theAllocator.dispose(foo); }
Dec 15 2016
prev sibling parent reply ag0aep6g <anonymous example.com> writes:
On 12/15/2016 06:44 PM, David Zhang wrote:
 It is my understanding that a class can have a struct as one of its
 members, and it will be allocated in-line with the rest of the class'
 members.
Yup.
 My question is this; how might I be able to do this with
 another class? I want to be able to allocate Foo using
 std.experimental.allocator without having to pass in a reference to the
 actual allocator.
Add a fixed-size array with an appropiate size to the class, and use std.conv.emplace to construct the object there: ---- class SomeClass {} class Foo { this() { import std.conv: emplace; sc = emplace!SomeClass(scStorage); } SomeClass sc; void[__traits(classInstanceSize, SomeClass)] scStorage; } void main() { import std.experimental.allocator: make; import std.experimental.allocator.mallocator: Mallocator; auto foo = Mallocator.instance.make!Foo; } ---- I haven't considered alignment here. I'm not sure if you have to. The GC will collect the sc object along with the parent Foo. Be cautious of that when you allow public access to sc. You can also replace the sc field with a method that creates the class reference on the fly (it's just a cast): ---- class Foo { this() { import std.conv: emplace; emplace!SomeClass(scStorage); } property SomeClass sc() { return cast(SomeClass) scStorage.ptr; } void[__traits(classInstanceSize, SomeClass)] scStorage; } ----
Dec 15 2016
parent reply David Zhang <straivers98 gmail.com> writes:
Thank you for your responses. Visitor, I don't want any reference 
to an allocator within the class if I can avoid it. ag0aep6g, 
thanks! That's what I was looking for. However, it leaves me with 
another question, how much (if any) space would the static array 
require from the class? It's not a strict necessity for me, but 
I'm curious.
Dec 15 2016
parent reply ag0aep6g <anonymous example.com> writes:
On 12/15/2016 09:51 PM, David Zhang wrote:
 However, it leaves me with another question, how
 much (if any) space would the static array require from the class?
Depends on SomeClass. The array's size is just the value of __traits(classInstanceSize, SomeClass). There's no overhead. You can print such stuff at compile time with pragma(msg, ...): ---- pragma(msg, __traits(classInstanceSize, SomeClass)); pragma(msg, Foo.scStorage.sizeof); /* same */ ----
Dec 15 2016
parent reply David Zhang <straivers98 gmail.com> writes:
On Thursday, 15 December 2016 at 21:08:51 UTC, ag0aep6g wrote:
 On 12/15/2016 09:51 PM, David Zhang wrote:
 However, it leaves me with another question, how
 much (if any) space would the static array require from the 
 class?
Depends on SomeClass. The array's size is just the value of __traits(classInstanceSize, SomeClass). There's no overhead. You can print such stuff at compile time with pragma(msg, ...): ---- pragma(msg, __traits(classInstanceSize, SomeClass)); pragma(msg, Foo.scStorage.sizeof); /* same */ ----
So the size of Foo would be the size of SomeClass plus members? ie. Is the size of the array stored too?
Dec 15 2016
parent reply ag0aep6g <anonymous example.com> writes:
On Thursday, 15 December 2016 at 21:37:34 UTC, David  Zhang wrote:
 So the size of Foo would be the size of SomeClass plus members? 
 ie. Is the size of the array stored too?
With these definitions: ---- class SomeClass {} class Foo { this() { import std.conv: emplace; emplace!SomeClass(scStorage); } property SomeClass sc() { return cast(SomeClass) scStorage.ptr; } void[__traits(classInstanceSize, SomeClass)] scStorage; } ---- the "instance size" of Foo is the size of a) Foo's hidden/implicit fields which all classes have, plus b) the size of scStorage which is Foo's only explicit field. The size of scStorage is the instance size of SomeClass (just the implicit fields here). The size/length of scStorage is known at compile-time. It's not stored in Foo.
Dec 15 2016
parent reply David Zhang <straivers98 gmail.com> writes:
 I haven't considered alignment here. I'm not sure if you have 
 to.
I though all classes were aligned to sizeof(size_t) boundaries? Wouldn't it then just be align(sizeof(size_t)) byte[__traits(classInstanceSize, SomeClass)] scStorage;
Dec 16 2016
parent ag0aep6g <anonymous example.com> writes:
On Friday, 16 December 2016 at 18:25:42 UTC, David  Zhang wrote:
 I though all classes were aligned to sizeof(size_t) boundaries?
I don't know.
 Wouldn't it then just be

 align(sizeof(size_t)) byte[__traits(classInstanceSize, 
 SomeClass)] scStorage;
I guess? I really don't have much of a clue here. Looking around a bit, I found std.traits.classInstanceAlignment which seems fitting. http://dlang.org/phobos/std_traits.html#classInstanceAlignment
Dec 16 2016