On Wednesday, 3 September 2025 at 03:09:45 UTC, Ali Çehreli wrote:
GC.calloc(bytesNeeded);

Again, I misled you there.

>      writeln("myClasses address: ", myClasses);
>
>      alias MyClassPtr = MyClass *;

That's not useful because the type MyClass is already a reference type, implemented as a pointer by the compiler.

Yes, pointer to a class type will make sense in some cases but not here.

>      MyClassPtr[10] myClassPtrs;

So, that could be MyClass[]. Note, not the objects but MyClass values will be stored there, which are references to MyClass objects.

>      foreach (i; 0 .. 9) {

I removed hard-coded 10 above because your loop was one less than 10 iterations.

Ali

Made some further changes, and have additional questions.

Console output:
```
myClassActualSize: 41
myPaddedClassSize: 48
bytesNeeded: 480
myClasses address: 25DF6931000

0: {a: 0, name: Sally, c: D}, &myClasses[i]: 25DF6932000, &myClasses[i].a: 25DF6931010 1: {a: 1, name: Sally, c: D}, &myClasses[i]: 25DF6932008, &myClasses[i].a: 25DF6931040 2: {a: 2, name: Sally, c: D}, &myClasses[i]: 25DF6932010, &myClasses[i].a: 25DF6931070 3: {a: 3, name: Sally, c: D}, &myClasses[i]: 25DF6932018, &myClasses[i].a: 25DF69310A0 4: {a: 4, name: Sally, c: D}, &myClasses[i]: 25DF6932020, &myClasses[i].a: 25DF69310D0 5: {a: 5, name: Sally, c: D}, &myClasses[i]: 25DF6932028, &myClasses[i].a: 25DF6931100 6: {a: 6, name: Sally, c: D}, &myClasses[i]: 25DF6932030, &myClasses[i].a: 25DF6931130 7: {a: 7, name: Sally, c: D}, &myClasses[i]: 25DF6932038, &myClasses[i].a: 25DF6931160 8: {a: 8, name: Sally, c: D}, &myClasses[i]: 25DF6932040, &myClasses[i].a: 25DF6931190 9: {a: 9, name: Sally, c: D}, &myClasses[i]: 25DF6932048, &myClasses[i].a: 25DF69311C0
```

source/app.d
```
import std.stdio;
import std.string;
import core.memory;
import core.lifetime;

void main()
{
        enum elementCount = 10;

    // Allocate room for 10 MyClass objects
immutable size_t myClassActualSize = __traits(classInstanceSize, MyClass);
    writeln("myClassActualSize: ", myClassActualSize);

    // ensure myClassSize is divisible by 8, to allow for padding
    immutable padding = 8;
    immutable size_t myPaddedClassSize =
        (myClassActualSize % padding == 0)
                        ? myClassActualSize
                        : (myClassActualSize + padding) / padding * padding;
    writeln("myPaddedClassSize: ", myPaddedClassSize);

    immutable bytesNeeded = myPaddedClassSize * elementCount;
    writeln("bytesNeeded: ", bytesNeeded);

    void* myClassObjects = GC.calloc(bytesNeeded);
    writeln("myClasses address: ", myClassObjects);

    // [Ali] Note the type of the array:
        //       MyClass is a reference to object; no pointer needed
    MyClass[] myClasses;

    foreach (i; 0 .. elementCount) {
        void * address = myClassObjects + (i * myPaddedClassSize);

// The first parameter guides emplace() of slice to instantiate MyClass instance. myClasses ~= emplace!MyClass(address[0 .. myPaddedClassSize], i, "Sally", 'D');
    }
        writeln;

        foreach (i; 0 .. elementCount) {
                writefln("%s: %s, &myClasses[i]: %s, &myClasses[i].a: %s",
                                  i, myClasses[i], &myClasses[i], 
&myClasses[i].a);
        }
}

class MyClass
{
    int a;
    string name;
    char c;

    this(int a, string name, char c) {
        this.a = a;
                this.name = name;
                this.c = c;
    }

        override string toString() const {
                return format("{a: %s, name: %s, c: %s}", a, name, c);
        }
}
```

Questions:
1. Is it necessary to pad myPaddedClassSize to an 8 byte granularity on 64 bit machine? If so, should emplace() be modified to provide the padding internally?

2. There is a 16 byte header before myClasses[0].a
   Is this for class overhead?

Reply via email to