destroy()中的访问冲突

bli*_*n17 3 destructor d destroy

我正在尝试使用手动内存管理从昂贵的对象管理生命周期,在我的单元测试期间,我似乎destroy(bar)在本示例中使用下方的main方法中的访问冲突导致我的程序崩溃.这是我遇到访问冲突的问题的最小示例.

我不明白出了什么问题.

class Foo { int i;}

struct Bar
{
    Foo _p;
    this(Foo foo)
    {
        _p = foo;
    }

    ~this() {
        import core.stdc.stdlib : free;
        if (_p !is null)
        {
            destroy(_p);
            free(cast(void*)_p);
            _p = null;
        }
    }
}


void main(string[] argv)
{
    import std.conv;
    import core.stdc.stdlib;

    Foo foo = emplace(cast(Foo) malloc(Foo.sizeof));

    Bar bar = Bar(foo);
    destroy(bar);
}
Run Code Online (Sandbox Code Playgroud)

Ada*_*ppe 5

请注意,destroy将_p设置为null"for"for you ...这意味着你永远不会释放它.做Foo tmp = _p; destroy(_p); free(cast(void*) tmp);替代,或者类似的东西,让你保持超越毁灭的呼叫参考的临时副本.这不是造成你的崩溃的原因,那只是内存泄漏.

崩溃是因为,Foo.sizeof类是引用的大小,而不是实例的大小.对于课程,你想要malloc(__traits(classInstanceSize, Foo)).文档提到这是其先决条件之一:http://dpldocs.info/experimental-docs/std.conv.emplace.3.html

这导致你的崩溃,因为你没有为vtable分配足够的空间(因此也可能会损坏内存,因为你的演员阵容导致了类型检查!).我会malloc并切片而不是铸造它.

// malloc the instance size then slice it to get a type-safe representation
void[] memory = malloc(__traits(classInstanceSize, Foo))[0 .. __traits(classInstanceSize, Foo)];
emplace!Foo(memory); // emplace a new one in that memory
Run Code Online (Sandbox Code Playgroud)

在将类引用传递给该结构时也应该小心,因为如果它没有被malloced或者如果有另一个引用,那么你将会遇到悬空问题.