Jump to page: 1 2
Thread overview
Delay allocating class instance in stack.
Mar 21, 2017
ANtlord
Mar 21, 2017
rikki cattermole
Mar 21, 2017
ANtlord
Mar 21, 2017
Ali Çehreli
Mar 22, 2017
ANtlord
Mar 22, 2017
Ali Çehreli
Mar 22, 2017
Ali Çehreli
Mar 22, 2017
ANtlord
Mar 22, 2017
Nicholas Wilson
Mar 23, 2017
ANtlord
Mar 21, 2017
Stefan Koch
Mar 22, 2017
ANtlord
March 21, 2017
Hello! I read documentation about memory management and can't find description about delay allocation of instance. I have a method marked by @nogc. This method takes boolean variable. If this variable is true I want to construct object with one set of parameters else I want to construct object with another set of parameters. Take a look at code for clearance.

void method(bool flag) @nogc
{
	scope MyClass obj;
	if(flag) {
		obj = new MyClass(1);
	} else {
		obj = new MyClass(2);
	}
	// using obj
}

But this code CAN'T be compiled. How should I declare object for delay construction.
Thanks.
March 21, 2017
You probably want[0] to allocate a class on the stack instead of doing this.

[0] http://dlang.org/phobos/std_typecons.html#.scoped
March 21, 2017
On Tuesday, 21 March 2017 at 08:12:36 UTC, rikki cattermole wrote:
> You probably want[0] to allocate a class on the stack instead of doing this.
>
> [0] http://dlang.org/phobos/std_typecons.html#.scoped

If I will use it I won't use @nogc. Is the only one case?
March 21, 2017
On 03/21/2017 01:08 AM, ANtlord wrote:
> void method(bool flag) @nogc
> {
>     scope MyClass obj;
>     if(flag) {
>         obj = new MyClass(1);
>     } else {
>         obj = new MyClass(2);
>     }
>     // using obj
> }

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

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

Ali

March 21, 2017
On Tuesday, 21 March 2017 at 08:08:24 UTC, ANtlord wrote:
> Hello! I read documentation about memory management and can't find description about delay allocation of instance. I have a method marked by @nogc. This method takes boolean variable. If this variable is true I want to construct object with one set of parameters else I want to construct object with another set of parameters. Take a look at code for clearance.
>
> void method(bool flag) @nogc
> {
> 	scope MyClass obj;
> 	if(flag) {
> 		obj = new MyClass(1);
> 	} else {
> 		obj = new MyClass(2);
> 	}
> 	// using obj
> }
>
> But this code CAN'T be compiled. How should I declare object for delay construction.
> Thanks.

Try scope obj = new MyClass(flag ? 1 : 2);

In essence you should never need to delay construction.
Just construct the object as soon as you have everything to construct it.
which includes conditions.
March 22, 2017
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?

March 22, 2017
On Tuesday, 21 March 2017 at 12:30:57 UTC, Stefan Koch wrote:
>
> Try scope obj = new MyClass(flag ? 1 : 2);
>
> In essence you should never need to delay construction.
> Just construct the object as soon as you have everything to construct it.
> which includes conditions.

Yes I know it. I prepare all input variables before construction of object usually. I just want to know possibilty of the case described above.
March 21, 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

March 21, 2017
On 03/21/2017 11:47 PM, Ali Çehreli wrote:

>     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

Answering own question: There are two destructor calls because I call method() twice.

Ali

March 22, 2017
On Wednesday, 22 March 2017 at 06:47:26 UTC, Ali Çehreli wrote:
> On 03/21/2017 09:57 PM, ANtlord wrote:
> > 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
>

Oh I got it. I have to use `destroy` in this case. If I use `scope` I haven't buffer and MyClass reference then I can don't use `destroy`. Do I understand correctly?

« First   ‹ Prev
1 2