Initialize class at given location

drug007 drug2004 at bk.ru
Fri Nov 28 21:43:32 UTC 2025


On 28.11.2025 22:32, Brother Bill wrote:
> On Friday, 28 November 2025 at 18:42:44 UTC, drug007 wrote:
>> On 28.11.2025 21:14, tzsz wrote:
>> In C++ it is called placement new. In D you should emplace class:
>>
> 
> This is quite helpful.  Could you provide another toy example where we 
> have abstract Vehicle class, then effective Car class derived from 
> Vehicle, then Toyota class derived from Car class. The Toyota class 
> needs to call Car constructor, which may need to call Vehicle 
> constructor, then complete its own constructor.
> Vehicle class has member of int speed (in Miles per hour), which will be 
> used in the example.  All classes have explicit constructors and 
> explicit destructors.
> 
> This example would complete the understanding of using emplace for me.
> Working examples that can be reproduced are the best teachers.
> 
> It is my understanding that using emplace as shown will make this class 
> pointer outside the scope of the GC.
> 
> Avoiding GC seems to be popular with Zig, Rust and other languages.
> It seems that D can play this game too.

It might look like this:

```D
import core.lifetime : emplace;
import std.stdio : writeln, writefln;
import std.experimental.allocator.mallocator : Mallocator;


abstract class Vehicle
{
     protected int speed;

     this(int initialSpeed)
     {
         this.speed = initialSpeed;
         writeln("Vehicle constructor called, speed: ", this.speed, " 
MPH.");
     }

     abstract void drive();

     ~this()
     {
         writeln("Vehicle destructor called.");
     }
}

class Car : Vehicle
{
     protected int wheels;

     this(int speed, int wheels)
     {
         super(speed); // Call Vehicle constructor
         this.wheels = wheels;
         writeln("Car constructor called, wheels: ", this.wheels);
     }

     override void drive()
     {
         writeln("A car is driving at ", speed, " MPH on ", wheels, " 
wheels.");
     }

     ~this()
     {
         writeln("Car destructor called.");
     }
}

class Toyota : Car
{
     protected string model;

     this(int speed, string model)
     {
         super(speed, 4); // Call Car constructor (which calls Vehicle's)
         this.model = model;
         writeln("Toyota constructor called, model: ", this.model);
     }

     // Toyota can use the drive method inherited from Car/Vehicle

     ~this()
     {
         writeln("Toyota destructor called.");
     }
}

void main()
{
     // Determine size needed for the concrete type we are emplacing 
(Toyota)
     enum size = __traits(classInstanceSize, Toyota);
     writeln("Size needed for Toyota instance: ", size, " bytes.");

     // Manually allocate memory using allocator, not C heap
     void[] rawMemory = Mallocator.instance.allocate(size);
     if (!rawMemory.ptr)
         throw new Exception("Out of memory!");
     writefln("Allocated raw memory address: %s, size: %s", 
rawMemory.ptr, rawMemory.length);

     // Using the slice above you can print the content of your instance
     writeln("\nUninitialized memory before Toyota instance construction");
     writefln("%(%02x %)\n", rawMemory);

     // Emplace the Toyota instance into the raw memory, calling its 
constructor
     // The constructors are called in order: Vehicle -> Car -> Toyota
     writeln("\n--- Emplacing the instance ---");
     auto myToyota = emplace!Toyota(cast(Toyota)rawMemory.ptr, 60, 
"Corolla");

     writeln("\nInitialized memory after Toyota instance construction");
     writefln("%(%02x %)\n", rawMemory);
     // it is offtopic but first 8 bytes are pointer to vtable,
     // next 8 bytes are so called monitor, so speed from Vehicle
     // is next 4 bytes and wheels amount is next 4 bytes,
     // next 8 bytes are length of the model name and
     // the last 8 bytes are the pointer to the model name

     // Use the instance
     writeln("\n--- Using the instance ---");
     myToyota.drive();
     myToyota.speed = 65; // Can modify inherited members
     myToyota.drive();

     writeln("\nInitialized memory after changing Toyota speed from 60 
to 65");
     writefln("%(%02x %)\n", rawMemory);

     // Manually destroy the object before freeing the memory
     writeln("\n--- Destroying the instance and freeing memory ---");
     // The destructors are called in reverse order: Toyota -> Car -> 
Vehicle
     destroy(myToyota);

     // Free the manually allocated raw memory
     Mallocator.instance.deallocate(rawMemory);
     writeln("Memory freed.");
}
```


More information about the Digitalmars-d-learn mailing list