在D中,对象是否可以在内部保存成员对象?

时间:2014-02-28 17:28:36

标签: memory-management reference d object-lifetime

在D中,可以使用scope在堆栈上分配类,即

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

现在,如果班级Foo将成员Bar作为成员,有没有办法在Bar内就地存储Foo并将其删除{ {1}} a la C ++?

我原本希望

Foo

会产生类似

的东西
  

酒吧
  富
  我是主要的!
  〜酒吧
  〜富

相反,我只得到

  


  我是主要的!
  〜富

将类成员存储为垃圾收集引用而不是就地存储似乎只是不必要地使堆布局复杂化而没有什么好处。如果没有指定暂时保留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!"); } ,那么scope在这种情况下做了什么?

3 个答案:

答案 0 :(得分:5)

不要使用范围类。这些都被有效地弃用,并且只是过去的遗产。有一个Phobos helper可以达到类似的效果。你的例子重写了:

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

答案 1 :(得分:2)

如果Bar是一个结构,你将得到你想要的,而不需要范围(但是,结构不能有默认构造函数,不允许writeln("Bar"))。除非你需要接口和虚函数,我认为结构通常是在D中使用的更好的工具,因为它们更灵活。你可以很容易地拥有一个具有确定性破坏,没有间接等的范围结构。如果你想让它成为一个引用,你总是可以使用指向它的指针或指向私有内部实现的指针来强制引用语义。

可以在结构中包装一个类,包括就地分配:

import std.stdio;

// bar is first because of https://d.puremagic.com/issues/show_bug.cgi?id=12278
class Bar {
    this() { writeln("Bar"); }
    ~this() { writeln("~Bar"); }
}


class Foo {
    this() {
        writeln("Foo");
        // since there's no default ctor for structs, we force
        // initialization right here
        inside = InPlace!Bar.getDefault();
    }

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

    // InPlace instead of scope...
    InPlace!Bar inside;
}

struct InPlace(T) {
    // an in-place buffer for the class data...
    private byte[__traits(classInstanceSize, T)] rawData;

    @property T obj() { return cast(T) rawData.ptr; }
    alias obj this; // DANGER: don't escape this reference!
    @disable this(); // force initialization at the usage site

    // get it default-constructed
    static InPlace!T getDefault() {
        InPlace!T t = void;
        t.initializeObject();
        t.obj.__ctor();
        return t;
    }

    void initializeObject() {
        assert(__traits(classInstanceSize, T) == 8);
        assert(T.classinfo.init.length == 8);
        assert(this.rawData.length == 8);
        this.rawData[] = T.classinfo.init[];
    }

    // ctors with args
    this(T...)(T t) {
        initializeObject();
        obj._ctor(t);
    }
    ~this() {
        .destroy(obj); // call the class destructor in the struct dtor
    }
}

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

编辑:std.typecons.scoped也这样做,我不确定它会在班级成员中起作用,但МихаилСтрашун的答案显示确实如此。 /编辑

那就行了......但我建议不要这样做。如果可以的话,你应该让Bar本身成为一个结构。这个包装器魔法的危险在于,如果你逃避对内部物体的引用,如果外部物体首先被摧毁,你可能会发生随机崩溃。如果它是私有的可能没问题,我想,虽然那里仍有一些危险(D中的私有模块私有,所以该模块中的另一个函数可能仍然会逃脱它,但是,如果你足够小心,你可以用它。)

跑步给出: 富 酒吧 我是主力! 〜富 〜酒吧

BTW您在OP中使用的范围当前已被弃用,因为它未安全/完全实现。我不认为它现在甚至堆栈分配,更像是在声明后立即自动插入scope(exit) .destroy(foo);

答案 2 :(得分:0)

您没有获得Bar~Bar,因为您从未创建该类的实例。