Delay allocating class instance in stack.

Ali Çehreli via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Tue Mar 21 23:47:26 PDT 2017


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



More information about the Digitalmars-d-learn mailing list