www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Delay allocating class instance in stack.

reply ANtlord <antlord92 gmail.com> writes:
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.
Mar 21
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
You probably want[0] to allocate a class on the stack instead of doing this.

[0] http://dlang.org/phobos/std_typecons.html#.scoped
Mar 21
parent ANtlord <antlord92 gmail.com> writes:
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?
Mar 21
prev sibling next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
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
Mar 21
parent reply ANtlord <antlord92 gmail.com> writes:
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?
Mar 21
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
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
Mar 21
next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
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
Mar 21
prev sibling parent reply ANtlord <antlord92 gmail.com> writes:
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?
Mar 22
parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Wednesday, 22 March 2017 at 08:57:34 UTC, ANtlord wrote:
 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?
You still have the buffer (the class has to go somewhere!), but it is implicit (you can't refer to it directly only through the class reference) and so is the destructor call, as opposed to the emplace + explicit buffer combo. In the latter case the class destructor will not be called automatically so you must do it yourself with `destroy`.
Mar 22
parent ANtlord <antlord92 gmail.com> writes:
On Wednesday, 22 March 2017 at 13:19:32 UTC, Nicholas Wilson 
wrote:
 On Wednesday, 22 March 2017 at 08:57:34 UTC, ANtlord wrote:
 You still have the buffer (the class has to go somewhere!), but 
 it is implicit (you can't refer to it directly only through the 
 class reference) and so is the destructor call, as opposed to 
 the emplace + explicit buffer combo. In the latter case the 
 class destructor will not be called automatically so you must 
 do it yourself with `destroy`.
My bad. It appears I need to clarify. I mean the case that I create object without delaying. I mean simple construction. scope myObj = MyClass(1); Answering own question: In this case object is allocated using stack (according documention https://wiki.dlang.org/Memory_Management#Allocating_Class_Inst nces_On_The_Stack). Function `destroy` used for cleanup object from heap (according documention https://wiki.dlang.org/Memory_Management#Explicit_Class_Instance_Allocation).
Mar 22
prev sibling parent reply Stefan Koch <uplink.coder googlemail.com> writes:
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.
Mar 21
parent ANtlord <antlord92 gmail.com> writes:
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.
Mar 21