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.");
}
```

Reply via email to