Debug help - Programming in D, page 670 allocate buffer of 10 MyClass class instances

Ali Çehreli acehreli at yahoo.com
Wed Sep 3 03:09:45 UTC 2025


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



More information about the Digitalmars-d-learn mailing list