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