On 9/2/25 4:51 PM, Brother Bill wrote:
> The code snippet from the book is:
> ```
>   // Allocate room for 10 MyClass objects
>   MyClass * buffer =
>       cast(MyClass*)GC.calloc(
>           __traits(classInstanceSize, MyClass) * 10);
> ```

For clarity, we are talking about this page:

  https://ddili.org/ders/d.en/memory.html

I was wrong there. MyClass* rarely makes sense. Casting GC.calloc that way is not useful at all.

> ```
> class MyClass
> {
>      int a;
>      string name;
>      char c;
> }
>
> ```
> MyClass is defined as a simple class, which requires padding after char
> c (intentionally).
> I want to use GC.calloc to allocate memory for 10 MyClass instances.
> But using __traits(classInstanceSize, MyClass) result in 41 bytes, which
> will require padding.
> So I manually add extra bytes to allow each MyClass instance to have an
> address divisible by 8.

Ok.

> Then I want to initialize them with with core.lifetime.emplace() with
> default constructor.
> Finally, use array index syntax to write to member variables. (This part
> breaks at run time)
>
> Hopefully, this will be interesting.
> Thank you for your assistance!
>
> Console when run:
> ```
> myClassActualSize: 41
> myPaddedClassSize: 48
> bytesNeeded: 480
> myClasses address: 2864A4A1000
> myClassPtrs[0]: 2864A4A1000
> i: 0, buffer: 2864A4A1000
>
>   *  The terminal process "C:
> \WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe -Command "&
> 'rdmd' 'c:\dev\D\81 - 90\c88_3c_GC_calloc_MyClass\source\app.d'""
> terminated with exit code: 1.
> ```
>
> source/app.d
> ```
> import std.stdio;
> import core.memory;
> import core.lifetime;
>
> void main()
> {
>      // 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 * 10;
>      writeln("bytesNeeded: ", bytesNeeded);
>      MyClass* myClasses = cast(MyClass *) 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.

>          myClassPtrs[i] = myClasses + i * myPaddedClassSize / padding;
>          writefln("myClassPtrs[%s]: %s ", i, myClassPtrs[i]);
>          auto buffer = cast(MyClass *) emplace(myClassPtrs[i]);
>          writefln("i: %s, buffer: %s", i, buffer);
>          writeln("i: %s, a: %s", i, myClassPtrs[i].a);        //

That's due to a syntax simplicity of D: Although your array element type is a pointer, D uses the dot instead of the arrow on the pointer, which redicets to the object.

So, the syntax above is actually this:

  (*myClassPtr[i]).a;

However, the elements are not MyClass references.

> Compiles. Run time hangs/exception
>      }
> }
>
> class MyClass
> {
>      int a;
>      string name;
>      char c;
> }
>
> ```

With apologies, I modified your code heavily with notes added as [Ali]:

import std.stdio;
import core.memory;
import core.lifetime;

void main()
{
    // 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);

    enum elementCount = 10;    // [Ali] Removing code duplication:

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

    // [Ali] Fixing my mistake by removing the cast:
    void* myClassObjects = GC.calloc(bytesNeeded);

    writeln("myClasses address: ", myClassObjects);

// [Ali] 1) Removing static array size not for correctness but just because
    // [Ali] 2) Note the type of the array: MyClass is a
    //          reference to object; no pointer needed
    // [Ali] 3) Renamed as myClasses
    MyClass[] myClasses;

    // [Ali] Replaced 9 with elementCount
    foreach (i; 0 .. elementCount) {
        // [Ali] 1) Removed cast because now it's already void*
        // [Ali] 2) Dividing by padding did not make sense
        auto address = myClassObjects + i * myPaddedClassSize;

        // [Ali] 1) Removed the index; just appending to the array
        //          (not necessary, just because...);
        // [Ali] 2) Used emplace to call the constructor (this
        //          works because I add a constructor below)
        // [Ali] 3) Note emplace's first parameter is a void slice
        myClasses ~= emplace!MyClass(address[0..myPaddedClassSize], i);

        writefln("myClasses[%s]: %s ", i, myClasses[i]);
        writefln("i: %s, a: %s", i, myClasses[i].a);
    }
}

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

    // [Ali] Added a constructor
    this(int a) {
        this.a = a;
    }
}


Ali

Reply via email to