Search code examples
memory-managementreferencedobject-lifetime

In D, is it possible for an object to hold a member object internally?


In D, it's possible to allocate classes on the stack using scope, i.e.

void foo()
{
    scope example = new Bar();
}

Now, if class Foo has class Bar as a member, is there any way to store Bar in-place inside Foo and have it tear down with Foo a la C++?

I had hoped that

import std.stdio;

class Foo {
    this() { writeln("Foo"); }

    ~this() { writeln("~Foo"); }

    scope Bar inside;
}

class Bar {

    this() { writeln("Bar"); }

    ~this() { writeln("~Bar"); }
};

void main()
{
    scope f = new Foo();
    writeln("I'm a main!");
}

would yield something like

Bar
Foo
I'm a main!
~Bar
~Foo

Instead I only get

Foo
I'm a main!
~Foo

It seems like storing a class member as a garbage-collected reference instead of in-place is just needlessly complicating the heap layout for little benefit. And what is scope doing in this case, if not specifying to hold Bar in-place?


Solution

  • Don't use scope classes. Those are effectively deprecated and remain only as legacy of old days. There is a Phobos helper that achieves similar effect. Your example re-written:

    import std.stdio;
    import std.typecons;
    
    alias ScopedBar = typeof(scoped!Bar());
    
    class Bar {
    
        this() { writeln("Bar"); }
    
        ~this() { writeln("~Bar"); }
    };
    
    class Foo
    {   
        this()
        {
            this.inside = scoped!Bar();
            writeln("Foo");
        }
    
        ~this() { writeln("~Foo"); }
    
        ScopedBar inside;
    }
    
    void main()
    {
        writeln("Main before scope");
        {
            auto f = scoped!Foo();
        }
        writeln("Main after scope");
    }