digitalmars.D.learn - move object from heap to stack
- Namespace (4/4) Sep 19 2012 Is that possible?
- Namespace (5/9) Sep 19 2012 I tried this:
- Simen Kjaeraas (8/17) Sep 19 2012 The problem here is that A.sizeof returns the size of the reference, not
- Namespace (2/2) Sep 19 2012 Thanks, I will use __traits(classInstanceSize, A);
- monarch_dodra (10/12) Sep 19 2012 This is because classes are already pointers. when you write
- Namespace (5/18) Sep 19 2012 I forget this. Thank you!
- Namespace (2/2) Sep 19 2012 Result:
- monarch_dodra (20/22) Sep 19 2012 I like it, but how can something placed on the stack be reference
- Namespace (7/7) Sep 19 2012 I count it to destroy it if it isn't used anymore.
- monarch_dodra (41/48) Sep 19 2012 What I'm saying though is that when your "stacked_obj" goes out
- Namespace (3/3) Sep 20 2012 You're right.
- monarch_dodra (35/38) Sep 20 2012 I think it looks good, but I'm unsure about "move", or allowing
- Johannes Pfau (26/69) Sep 20 2012 http://dlang.org/struct.html
- monarch_dodra (12/21) Sep 20 2012 True... the term "copy constructor" is not 100% accurate, it is
- Namespace (7/7) Sep 20 2012 So I should disable the copy ctor (@disable this(this)) and drop
- monarch_dodra (9/15) Sep 20 2012 Yes, but at that point, what you have is scoped!T re-implemented
- Namespace (11/26) Sep 20 2012 http://dpaste.dzfl.pl/edit/361a54eb
- monarch_dodra (2/12) Sep 20 2012 Wrong link.
- Namespace (3/15) Sep 20 2012 Try this: http://dpaste.dzfl.pl/9247af54
- monarch_dodra (15/33) Sep 20 2012 What did you expect? You are passing your OnStack by value. In
- Namespace (4/4) Sep 20 2012 I expect nothing, my only intention was to show you, that this
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (10/20) Sep 20 2012 A polymorphic member function would be better for when A is just a base
- Johannes Pfau (26/29) Sep 20 2012 I think it shouldn't be possible to copy an OnStack struct. The
- bearophile (4/6) Sep 20 2012 What's the point of doing it?
Is that possible? I can initialize an object with scope or, in feature, with scoped, directly on the stack but is it also possible to move an existing object from the heap to the stack?
Sep 19 2012
On Wednesday, 19 September 2012 at 13:32:42 UTC, Namespace wrote:Is that possible? I can initialize an object with scope or, in feature, with scoped, directly on the stack but is it also possible to move an existing object from the heap to the stack?I tried this: http://dpaste.dzfl.pl/2955ff41 But as you can see in line 25/26, after I destroyed the heap object, the stack object seems to be corrupted.
Sep 19 2012
On Wed, 19 Sep 2012 15:45:21 +0200, Namespace <rswhite4 googlemail.com> wrote:On Wednesday, 19 September 2012 at 13:32:42 UTC, Namespace wrote:The problem here is that A.sizeof returns the size of the reference, not the instance. Instead you should use __traits(classInstanceSize, A). Also, do have a look at the internals of std.typecons.scoped, it likely contains some good ideas. -- SimenIs that possible? I can initialize an object with scope or, in feature, with scoped, directly on the stack but is it also possible to move an existing object from the heap to the stack?I tried this: http://dpaste.dzfl.pl/2955ff41 But as you can see in line 25/26, after I destroyed the heap object, the stack object seems to be corrupted.
Sep 19 2012
Thanks, I will use __traits(classInstanceSize, A); But it does not work either.
Sep 19 2012
On Wednesday, 19 September 2012 at 14:16:31 UTC, Namespace wrote:Thanks, I will use __traits(classInstanceSize, A); But it does not work either.This is because classes are already pointers. when you write "&a", you are getting the address of pointer itself. So when you memcopy, don't use "&a", but use "cast(void*)a". What you were currently doing was memcopying the "pointer to a" into your chunk. From there, since you were casting to A*, everything worked and was legal, but you still only had 1 class intance. Your destroying that instance made your ap crash. this works: http://dpaste.dzfl.pl/8ba1f457
Sep 19 2012
On Wednesday, 19 September 2012 at 17:08:28 UTC, monarch_dodra wrote:On Wednesday, 19 September 2012 at 14:16:31 UTC, Namespace wrote:I forget this. Thank you! IMO something like this should exist in phobos. A more flexible version of scoped also.Thanks, I will use __traits(classInstanceSize, A); But it does not work either.This is because classes are already pointers. when you write "&a", you are getting the address of pointer itself. So when you memcopy, don't use "&a", but use "cast(void*)a". What you were currently doing was memcopying the "pointer to a" into your chunk. From there, since you were casting to A*, everything worked and was legal, but you still only had 1 class intance. Your destroying that instance made your ap crash. this works: http://dpaste.dzfl.pl/8ba1f457
Sep 19 2012
On Wednesday, 19 September 2012 at 19:24:34 UTC, Namespace wrote:Result: http://dpaste.dzfl.pl/24988d8fI like it, but how can something placed on the stack be reference counted? The "chunk" is also placed on the stack, so it doesn't really make sense to me: When the object goes out of scope, the chunk goes, regardless of ref count. I think you should ditch the whole ref count thing. You'll also have to be aware of the dangers of putting a class instance on the stack: main() { A a; { stacked_obj!A so; so.gen; a = so.get; } a.print(); //<-- undefined, with or without reference count } IE: Big red comment you should NEVER extract an instance from the stack.
Sep 19 2012
I count it to destroy it if it isn't used anymore. I can remove this behaviour but IMO with this you haven't unnecessary use of stack memory. Am I wrong? Furthermore, if I copy the stack object e.g. if I pass it as value parameter to another function/class, I can store it as long as it's needed. Maybe that should be the task of the heap, but I'm not sure.
Sep 19 2012
On Wednesday, 19 September 2012 at 21:36:56 UTC, Namespace wrote:I count it to destroy it if it isn't used anymore.What I'm saying though is that when your "stacked_obj" goes out of scope, it gets destroyed, 100% of the time. The "chunk" disappears, along with any object inside it. When that happens, it doesn't matter what the count is, whatever is inside chunk MUST be destroyed.I can remove this behaviour but IMO with this you haven't unnecessary use of stack memory. Am I wrong?Yes, because all your stacked_obj have a chunk member variable. The reference count doesn't change that. When you pass by value, a new chunk is created an copied. Your postblit is weird: this(this) { this._use_counter++; this._use_counter = _use_counter; } The way postblit works is that first, the "other" is memcopyed onto this. Then, postblit modifies the current object. "this._use_counter = _use_counter;" makes no sense. One more thing: You can't memcopy a class from one place to another, because you don't know if it has a CC or not. You *could* swap the class, which would be safe for the class itself, but not for anything else referencing the class.Furthermore, if I copy the stack object e.g. if I pass it as value parameter to another function/class, I can store it as long as it's needed. Maybe that should be the task of the heap, but I'm not sure.Yes, but technically, you are still passing a copy. Anyways, I re-read scoped's implementation, and classes ARE allocated on the stack. Further more, they can emplace their new object. They can also copy an existing class into them... provided the class gives access to CC. It is not a move, but, IMO, a move would be unsafe anyways. import std.typecons; class A { this(){} this(int){} this(A){} } void main() { auto sa = scoped!A(new A()); auto sb = scoped!A(5); } I'm not entirely.
Sep 19 2012
You're right. This is my next try: http://dpaste.dzfl.pl/02b32d33 Do you have anything else to say? :)
Sep 20 2012
On Thursday, 20 September 2012 at 08:10:36 UTC, Namespace wrote:You're right. This is my next try: http://dpaste.dzfl.pl/02b32d33 Do you have anything else to say? :)I think it looks good, but I'm unsure about "move", or allowing pass by value: Classes can't be memcopied the way structs can: Class may have default constructors, or copy constructors, which would be totally ignored by a memcopy. For example, if your class had a "RefCounted" member, its postblit would never be called, and it would then be "over destroyed": -------- class A { RefCounted!int rf; this() { rf.RefCounted.ensureInitialized(); rf = 5; } } void main() { A a = new A(); OnStack!A osa = OnStack!A.move(a); } -------- core.exception.InvalidMemoryOperationError -------- Here, osa makes a binary copy of the RefCounted, so the count stays at 1. Then, when osa is destroyed, it deletes the RefCounted's store. However, when a is destroyed, it still has a pointer to the (deleted) store, creating the Error... I think "move" has to go, because classes are just not moveable. pass by value can stay, if and only if, T gives a copy constructor. Or NO constructors (in which case a memcopy should be the same as a default copy).
Sep 20 2012
Am Thu, 20 Sep 2012 12:06:28 +0200 schrieb "monarch_dodra" <monarchdodra gmail.com>:On Thursday, 20 September 2012 at 08:10:36 UTC, Namespace wrote:http://dlang.org/struct.html D classes do not really have copy constructors. You could assume that if a constructor has only one argument and it's of the same type as the class, it's a copy constructor. But that's a pure convention then, nothing than could be enforced in any way. Copying classes is dangerous, and problems can also happen without constructors: ---------- class A { void* handle; ~this() { if(handle) free(handle); } } { auto a = OnStack!A(); a.handle = someHandle; auto b = a; //copy } //end of scope, someHandle is freed twice ---------- This can even happen if the class does not keep any reference types. The example would also be valid with a file handle (uint).You're right. This is my next try: http://dpaste.dzfl.pl/02b32d33 Do you have anything else to say? :)I think it looks good, but I'm unsure about "move", or allowing pass by value: Classes can't be memcopied the way structs can: Class may have default constructors, or copy constructors, which would be totally ignored by a memcopy. For example, if your class had a "RefCounted" member, its postblit would never be called, and it would then be "over destroyed": -------- class A { RefCounted!int rf; this() { rf.RefCounted.ensureInitialized(); rf = 5; } } void main() { A a = new A(); OnStack!A osa = OnStack!A.move(a); } -------- core.exception.InvalidMemoryOperationError -------- Here, osa makes a binary copy of the RefCounted, so the count stays at 1. Then, when osa is destroyed, it deletes the RefCounted's store. However, when a is destroyed, it still has a pointer to the (deleted) store, creating the Error... I think "move" has to go, because classes are just not moveable. pass by value can stay, if and only if, T gives a copy constructor. Or NO constructors (in which case a memcopy should be the same as a default copy).
Sep 20 2012
On Thursday, 20 September 2012 at 10:20:24 UTC, Johannes Pfau wrote:http://dlang.org/struct.html D classes do not really have copy constructors. You could assume that if a constructor has only one argument and it's of the same type as the class, it's a copy constructor.True... the term "copy constructor" is not 100% accurate, it is just "a constructor that takes the same type" A a = new A(); //Creates a new A A b = a; //Binds to the existing A A c = new A(a); //Constructs a new A, form an old A.But that's a pure convention then, nothing than could be enforced in any way. Copying classes is dangerous, and problems can also happen without constructors: [SNIP]Yes, that is a good point. I could find ways to make it crash even with a POD class, so I guess we could relax the condition to "don't ever memcpy a class: They aren't designed for that. Bad! Bad! Don't do it!" I'm learning from this thread.
Sep 20 2012
So I should disable the copy ctor ( disable this(this)) and drop move, right? As you can See if I pass a OnStack to function/class i'm using .get all the Time. The only other method IMO would be to pass it as OnStack by value and Store it in the other class also as OnStack, right? bearophiole: just to Know if something lile this is possible.
Sep 20 2012
On Thursday, 20 September 2012 at 12:32:03 UTC, Namespace wrote:So I should disable the copy ctor ( disable this(this)) and drop move, right?Yes, but at that point, what you have is scoped!T re-implemented :/As you can See if I pass a OnStack to function/class i'm using .get all the Time.You could "alias get this". This way, your OnStack will call cast as a T implicitly. Again, this is what scoped!T does.The only other method IMO would be to pass it as OnStack by value and Store it in the other class also as OnStack, right?Yes, but that would require a copy contructor "this(this)", which we have actually ruled out. You can pass the T itself thanks to the implicit cast to T, but you can't pass an actual OnStack object.
Sep 20 2012
On Thursday, 20 September 2012 at 14:02:01 UTC, monarch_dodra wrote:On Thursday, 20 September 2012 at 12:32:03 UTC, Namespace wrote:http://dpaste.dzfl.pl/edit/361a54eb With [code] disable this(this); [/code] this don't work (as expected). But with the copy ctor but without ".get" you earn a segmentation fault (as you can see). So you can disable the copy ctor but without using .get you're not get what you want. Even with scoped, but scoped's getter name is too long.So I should disable the copy ctor ( disable this(this)) and drop move, right?Yes, but at that point, what you have is scoped!T re-implemented :/As you can See if I pass a OnStack to function/class i'm using .get all the Time.You could "alias get this". This way, your OnStack will call cast as a T implicitly. Again, this is what scoped!T does.The only other method IMO would be to pass it as OnStack by value and Store it in the other class also as OnStack, right?Yes, but that would require a copy contructor "this(this)", which we have actually ruled out. You can pass the T itself thanks to the implicit cast to T, but you can't pass an actual OnStack object.
Sep 20 2012
On Thursday, 20 September 2012 at 14:09:29 UTC, Namespace wrote:http://dpaste.dzfl.pl/edit/361a54eb With [code] disable this(this); [/code] this don't work (as expected). But with the copy ctor but without ".get" you earn a segmentation fault (as you can see). So you can disable the copy ctor but without using .get you're not get what you want. Even with scoped, but scoped's getter name is too long.Wrong link.
Sep 20 2012
On Thursday, 20 September 2012 at 14:15:23 UTC, monarch_dodra wrote:On Thursday, 20 September 2012 at 14:09:29 UTC, Namespace wrote:Try this: http://dpaste.dzfl.pl/9247af54http://dpaste.dzfl.pl/edit/361a54eb With [code] disable this(this); [/code] this don't work (as expected). But with the copy ctor but without ".get" you earn a segmentation fault (as you can see). So you can disable the copy ctor but without using .get you're not get what you want. Even with scoped, but scoped's getter name is too long.Wrong link.
Sep 20 2012
On Thursday, 20 September 2012 at 15:04:48 UTC, Namespace wrote:On Thursday, 20 September 2012 at 14:15:23 UTC, monarch_dodra wrote:What did you expect? You are passing your OnStack by value. In this particular case, you are over destroying your OnStack!B, which in turn over destroyes his _a. Reactivate the disable, and you'll see the problem blatantly: http://dpaste.dzfl.pl/9e873033 /home/c192/c104.d(102): Error: struct c104.OnStack!(A).OnStack is not copyable because it is annotated with disable The "problem" with implicit cast is that *sometimes* you think it does it, but in fact, it doesn't. Here, it didn't. The opCall expects Arg... so if you give it an OnStack, it accepts an OnStack. If you want it to take a T, you have to specify it, either in the template, or with get, or with a cast. Here is a cast version, with this(this) disabled: http://dpaste.dzfl.pl/837f44a9On Thursday, 20 September 2012 at 14:09:29 UTC, Namespace wrote:Try this: http://dpaste.dzfl.pl/9247af54http://dpaste.dzfl.pl/edit/361a54eb With [code] disable this(this); [/code] this don't work (as expected). But with the copy ctor but without ".get" you earn a segmentation fault (as you can see). So you can disable the copy ctor but without using .get you're not get what you want. Even with scoped, but scoped's getter name is too long.Wrong link.
Sep 20 2012
I expect nothing, my only intention was to show you, that this cannot work. But that it works with an explicit cast is very impressive. I thought the alias this does it automatically. I'm learning too. ;)
Sep 20 2012
On 09/20/2012 03:37 AM, monarch_dodra wrote:On Thursday, 20 September 2012 at 10:20:24 UTC, Johannes Pfau wrote:A polymorphic member function would be better for when A is just a base class, i.e. when we don't know its actual type (the virtual constructor idiom): void foo(Animal a) { Animal c = a.dup; // can be any Animal // ... } Alihttp://dlang.org/struct.html D classes do not really have copy constructors. You could assume that if a constructor has only one argument and it's of the same type as the class, it's a copy constructor.True... the term "copy constructor" is not 100% accurate, it is just "a constructor that takes the same type" A a = new A(); //Creates a new A A b = a; //Binds to the existing A A c = new A(a); //Constructs a new A, form an old A.
Sep 20 2012
Am Thu, 20 Sep 2012 10:11:37 +0200 schrieb "Namespace" <rswhite4 googlemail.com>:You're right. This is my next try: http://dpaste.dzfl.pl/02b32d33 Do you have anything else to say? :)I think it shouldn't be possible to copy an OnStack struct. The destructor is run for every copy, but the constructor was run only once. So if a class keeps external references (e.g. file handles) and closes those handles in the destructor, making a copy would result in the destructor running twice and therefore closing the same handle twice. I think the usage of a OnStack struct must be quite limited to be safe: { auto a = OnStack!(A)(); //allocate in scope a.doSomething(); //Calling members is fine //a.get and a must not escape this scope (I guess we can't guarantee //that without compiler help?) //passing a.get to a function is valid, as long as the function //doesn't keep a reference (the function parameter must be marked //with scope) someMethod(a.get); //As a shouldn't be copied, an OnStack can't be passed to another //function. //no copies for OnStack allowed //destroy at end of scope } Those rules are pretty strict, but maybe that's the only way to have a safe OnStack. Maybe I forgot some detail and those rules aren't even strict enough.
Sep 20 2012
Namespace:is it also possible to move an existing object from the heap to the stack?What's the point of doing it? Bye, bearophile
Sep 20 2012