On 03/21/2017 09:57 PM, ANtlord wrote:
> On Tuesday, 21 March 2017 at 08:46:43 UTC, Ali Çehreli wrote:
>> Another option is std.conv.emplace:
>>
>> import std.conv : emplace;
>>
>> class MyClass {
>>     this(int) @nogc {
>>     }
>>
>>     ~this() @nogc {
>>     }
>> }
>>
>> void method(bool flag) @nogc
>> {
>>     void[__traits(classInstanceSize, MyClass)] buffer = void;
>>     MyClass obj;
>>
>>     if(flag) {
>>         obj = emplace!MyClass(buffer, 1);
>>     } else {
>>         obj = emplace!MyClass(buffer, 2);
>>     }
>>
>>     // Unfortunately, destroy() is not @nogc
>>     // scope(exit) destroy(obj);
>
> Thank you for clarification. But I have one more question. Do I have to
> use destroy for deallocating object from stack?

Yes because what is going out of scope are two things:

- A buffer
- A MyClass reference

Neither of those have destructors. (emplace is just a library function that does something with that buffer but the compiler cannot know that there is an object that we want destructed.)

Here is a hack that defines a destroyNoGC() that allows one to call the destructor is a @nogc context:

import std.stdio;
import std.conv : emplace;

class MyClass {
    this(int) @nogc {
    }

    ~this() @nogc {
        printf("~this\n");
    }
}

// Adapted from std.traits.SetFunctionAttributes documentation
import std.traits;
auto assumeNoGC(T)(T t)
    if (isFunctionPointer!T || isDelegate!T)
{
    enum attrs = functionAttributes!T | FunctionAttribute.nogc;
    return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t;
}

@nogc void function(Object) destroyNoGC;
static this() {
    destroyNoGC = assumeNoGC((Object obj) {
        destroy(obj);
    });
}

void method(bool flag) @nogc
{
    void[__traits(classInstanceSize, MyClass)] buffer = void;
    MyClass obj;

    if(flag) {
        obj = emplace!MyClass(buffer, 1);
    } else {
        obj = emplace!MyClass(buffer, 2);
    }

    scope(exit) {
        destroyNoGC(obj);
    }
}

void main() {
    method(false);
    method(true);
}

Gotta love D for allowing such code but it comes with surprises. Why do we suddenly get two destructor calls?

~this
~this

Ali

Reply via email to