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