digitalmars.D - Allocating structs with new?
- Jonathan M Davis (26/26) Jul 09 2010 I thought that classes always went on the heap and that structs always w...
- bearophile (5/7) Jul 09 2010 Structs can be allocated on the heap, and then referenced by pointer. Th...
- Justin Johansson (9/19) Jul 10 2010 With care? That doesn't say very much except for possibly an
- Robert Jacques (17/55) Jul 09 2010 A new statement can also allocate value types on the heap and return a
- Jonathan M Davis (16/24) Jul 10 2010 I guess that I missed that, though it doesn't help that I've read the cl...
- Justin Johansson (24/50) Jul 10 2010 Don't blame it on any lack on your part to pick up on D's subtleties;
- div0 (5/7) Jul 10 2010 So what are we going to use instead? I have uses for delete.
- Robert Jacques (3/7) Jul 10 2010 clear is meant to be a safe version of delete.
- div0 (10/20) Jul 10 2010 Yeah I don't care about safe. Safe D can never happen at all for all I c...
- Simen kjaeraas (5/9) Jul 10 2010 druntime's gc.gc has extern (C) void gc_free( void* p ). That
- Adam Ruppe (15/19) Jul 10 2010 D is very similar to C++ here, with the big exception that classes
- Leandro Lucarella (15/20) Jul 10 2010 You don't need a vtable, because you don't have inheritance with
- Robert Jacques (5/17) Jul 10 2010 :) That's sort-of what I meant by a vtable. (Either it being one functio...
- bearophile (4/6) Jul 11 2010 Structs are simpler for the compiler, help you produce a smaller program...
- bearophile (8/11) Jul 11 2010 I probably meant something different.
- Justin Johansson (7/22) Jul 12 2010 I probably meant something different too and also remiss of me
- Steven Schveighoffer (21/58) Jul 12 2010 structs on the heap are a necessity. Classes are too heavyweight for
- Andrei Alexandrescu (6/10) Jul 12 2010 Concrete scenarios of structs ending up on the hap often involve classes...
- bearophile (5/7) Jul 12 2010 In this bug report, comment 6, I have asked for a warning, but turning i...
I thought that classes always went on the heap and that structs always went on the stack - so allocating structs with new wouldn't work. Also, I thought that delete was deprecated if not outright removed from D. And yet, we have a new bug that Andrei reported about destructors for structs not working correctly when they're allocated with new (and delete is being used to destroy it in the code in the report). http://d.puremagic.com/issues/show_bug.cgi?id=4442 Code from bug report: struct S1{ ~this() { writeln("dtor"); } } void main() { auto a = S1(); auto b = new S1(); delete b; auto c = new S1(); c = null; GC.collect(); } Am I missing something here? TDPL was quite clear that classes were reference types and structs were value types, and here we appear to have a struct used as a reference type. Is this some sort of feature from outside of SafeD, or is it a feature that was supposed to be removed but hasn't yet, or what? I know that TDPL doesn't cover everything and that what dmd does doesn't always match it yet, but from what I understood from reading TDPL, the code above shouldn't compile at all since it's using a struct like a class and is using the supposedy defunct delete operator. - Jonathan M Davis
Jul 09 2010
Jonathan M Davis Wrote:I thought that classes always went on the heap and that structs always went on the stackStructs can be allocated on the heap, and then referenced by pointer. This is not something I can live without. Explicit delete is a problem with a language based on GC, it has to be removed with care. Bye, bearophile
Jul 09 2010
bearophile wrote:Jonathan M Davis Wrote:With care? That doesn't say very much except for possibly an unintended suggestion that the OP is not trying to use care. He is posting because he does care. Sorry bearophile, but can you please better explain in the context of the OP's original dilemma just what kind of care is needed to bake this cookie. Cheers, Justin JohanssonI thought that classes always went on the heap and that structs always went on the stackStructs can be allocated on the heap, and then referenced by pointer. This is not something I can live without. Explicit delete is a problem with a language based on GC, it has to be removed with care. Bye, bearophile
Jul 10 2010
On Sat, 10 Jul 2010 01:06:39 -0400, Jonathan M Davis <jmdavisprog gmail.com> wrote:I thought that classes always went on the heap and that structs always went on the stack - so allocating structs with new wouldn't work. Also, I thought that delete was deprecated if not outright removed from D. And yet, we have a new bug that Andrei reported about destructors for structs not working correctly when they're allocated with new (and delete is being used to destroy it in the code in the report). http://d.puremagic.com/issues/show_bug.cgi?id=4442 Code from bug report: struct S1{ ~this() { writeln("dtor"); } } void main() { auto a = S1(); auto b = new S1(); delete b; auto c = new S1(); c = null; GC.collect(); } Am I missing something here? TDPL was quite clear that classes were reference types and structs were value types, and here we appear to have a struct used as a reference type. Is this some sort of feature from outside of SafeD, or is it a feature that was supposed to be removed but hasn't yet, or what? I know that TDPL doesn't cover everything and that what dmd does doesn't always match it yet, but from what I understood from reading TDPL, the code above shouldn't compile at all since it's using a struct like a class and is using the supposedy defunct delete operator. - Jonathan M DavisA new statement can also allocate value types on the heap and return a pointer to them. For example, the type of b and c is S1* and the GC doesn't know about C's destructor. Please refer to the D spec on new (http://www.digitalmars.com/d/2.0/expression.html#NewExpression) or TDPL page 51. Both state that any type can be used with new; no limitations with regard to reference or non-reference types are mentioned. Also, on page 269 of TDPL there is an example of containing a Node*. As for the bug, it's actually somewhat old. Issue 2834 was filed back in April of 09 - Struct Destructors are not called by the GC, but called on explicit delete. And this is a bug in the spec, not DMD; the only way to run struct destructors from the GC is to add vtables to them or hidden in the GC (i.e. to make them classes). By the way, structs inside of classes do get their destructors called. As for delete and clear, the deprecation/transition is still in progress. clear exists, but delete is not deprecated yet.
Jul 09 2010
On Friday 09 July 2010 23:31:18 Robert Jacques wrote:A new statement can also allocate value types on the heap and return a pointer to them. For example, the type of b and c is S1* and the GC doesn't know about C's destructor. Please refer to the D spec on new (http://www.digitalmars.com/d/2.0/expression.html#NewExpression) or TDPL page 51. Both state that any type can be used with new; no limitations with regard to reference or non-reference types are mentioned. Also, on page 269 of TDPL there is an example of containing a Node*.I guess that I missed that, though it doesn't help that I've read the class and struct chapters more recently, and they made a big deal about how classes were reference type and structs were value types and may no mention whatsoever of using structs on the heap - that and I rarely use pointers with primitive types even in C++, and I pretty much never use pointers in D. I think that I was thinking that you had to use malloc to put primitive types no the heap though. It never occurred to me to put a struct on the heap. Obviously, it's not a feature that I use often. I don't mind that it be possible with new, but it is potentially confusing. Oh well, at least I'm aware of it now. If I ever want to use new in that manner though, I'm obviously going to have to study up on the subject more. I'm quite clear about how all that works in languages like C++ or Java, but D is a bit of a hybrid when it comes to memory management, and I obviously haven't pick up on all of its subtleties yet. - Jonathan M Davis
Jul 10 2010
Jonathan M Davis wrote:On Friday 09 July 2010 23:31:18 Robert Jacques wrote:Don't blame it on any lack on your part to pick up on D's subtleties; I feel your pain also. A clean programming language should aspire to removing such subtleties. Recall the "D manifesto" on the D home page if one can call that a manifesto. <quote from-url="http://www.digitalmars.com/d/"> D is a systems programming language. Its focus is on combining the power and high performance of C and C++ with the programmer productivity of modern languages like Ruby and Python. Special attention is given to the needs of quality assurance, documentation, management, portability and reliability. </quote> Now take challenge to that "manifesto" and ask "Who is kidding who?" Sorry, Walter & Co, but there is a long way to go or otherwise time to start over. Even the Scala people have had the decency to question themselves as to whether their language was an experiment. See the Scala experiment: lampwww.epfl.ch/~odersky/talks/popl06.pdf My apologies for sometimes sounding pro-D and then sometimes contra-D. Overall I think that the goals of D are admirable but then so much lost in the realization. Cheers Justin JohanssonA new statement can also allocate value types on the heap and return a pointer to them. For example, the type of b and c is S1* and the GC doesn't know about C's destructor. Please refer to the D spec on new (http://www.digitalmars.com/d/2.0/expression.html#NewExpression) or TDPL page 51. Both state that any type can be used with new; no limitations with regard to reference or non-reference types are mentioned. Also, on page 269 of TDPL there is an example of containing a Node*.I guess that I missed that, though it doesn't help that I've read the class and struct chapters more recently, and they made a big deal about how classes were reference type and structs were value types and may no mention whatsoever of using structs on the heap - that and I rarely use pointers with primitive types even in C++, and I pretty much never use pointers in D. I think that I was thinking that you had to use malloc to put primitive types no the heap though. It never occurred to me to put a struct on the heap. Obviously, it's not a feature that I use often. I don't mind that it be possible with new, but it is potentially confusing. Oh well, at least I'm aware of it now. If I ever want to use new in that manner though, I'm obviously going to have to study up on the subject more. I'm quite clear about how all that works in languages like C++ or Java, but D is a bit of a hybrid when it comes to memory management, and I obviously haven't pick up on all of its subtleties yet. - Jonathan M Davis
Jul 10 2010
On 10/07/2010 07:31, Robert Jacques wrote:As for delete and clear, the deprecation/transition is still in progress. clear exists, but delete is not deprecated yet.So what are we going to use instead? I have uses for delete. -- My enormous talent is exceeded only by my outrageous laziness. http://www.ssTk.co.uk
Jul 10 2010
On Sat, 10 Jul 2010 10:01:52 -0400, div0 <div0 users.sourceforge.net> wrote:On 10/07/2010 07:31, Robert Jacques wrote:clear is meant to be a safe version of delete.As for delete and clear, the deprecation/transition is still in progress. clear exists, but delete is not deprecated yet.So what are we going to use instead? I have uses for delete.
Jul 10 2010
On 10/07/2010 18:04, Robert Jacques wrote:On Sat, 10 Jul 2010 10:01:52 -0400, div0 <div0 users.sourceforge.net> wrote:Yeah I don't care about safe. Safe D can never happen at all for all I care. If clear doesn't return the memory to the free list it's fecking useless to me; I have a need for deterministic memory allocation. If new D is going to require a GC it's no longer a systems programming language and it's no longer either interesting or an appropriate replacement for C++. -- My enormous talent is exceeded only by my outrageous laziness. http://www.ssTk.co.ukOn 10/07/2010 07:31, Robert Jacques wrote:clear is meant to be a safe version of delete.As for delete and clear, the deprecation/transition is still in progress. clear exists, but delete is not deprecated yet.So what are we going to use instead? I have uses for delete.
Jul 10 2010
div0 <div0 users.sourceforge.net> wrote:On 10/07/2010 07:31, Robert Jacques wrote:druntime's gc.gc has extern (C) void gc_free( void* p ). That probably is what you want. -- SimenAs for delete and clear, the deprecation/transition is still in progress. clear exists, but delete is not deprecated yet.So what are we going to use instead? I have uses for delete.
Jul 10 2010
On 7/10/10, Jonathan M Davis <jmdavisprog gmail.com> wrote:I think that I was thinking that you had to use malloc to put primitive types no the heap though.D is very similar to C++ here, with the big exception that classes *must* use new, whereas new is just an option for everything else. int* a = new int; // valid C++ and D struct S {} S* s = new S; // same as int case, works in C++ and D bothI don't mind that it be possible with new, but it is potentially confusing.The thing that might be confusing in the example is the auto keyword hides the fact that you were working with a pointer (S*) instead of the object itself (S). Since D doesn't have the -> operator like C++, working with the S and the S* is the same in most ways, so they look virtually identical. But as far as new's functionality, that's the same as C++, returning a pointer to a heap allocated whatever you want. Oh, there is one big difference between D and C++ new: in D, it is garbage collected, so you never have to call delete explicitly.
Jul 10 2010
Robert Jacques, el 10 de julio a las 02:31 me escribiste:As for the bug, it's actually somewhat old. Issue 2834 was filed back in April of 09 - Struct Destructors are not called by the GC, but called on explicit delete. And this is a bug in the spec, not DMD; the only way to run struct destructors from the GC is to add vtables to them or hidden in the GC (i.e. to make them classes).You don't need a vtable, because you don't have inheritance with structs. All you need is a function pointer pointing to the finalization function/method. This plays well with the concept of having type information associated to blocks of memory in the GC, which means (semi)precise heap scanning. So maybe is not a bad idea to make the destructors of structs get called by the GC :) -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Debemos creer en los sueños del niño. Cuando el niño sueña con tetas, se toca. -- Ricardo Vaporeso. Toulouse, 1915.
Jul 10 2010
On Sat, 10 Jul 2010 18:17:21 -0400, Leandro Lucarella <luca llucax.com.ar> wrote:Robert Jacques, el 10 de julio a las 02:31 me escribiste::) That's sort-of what I meant by a vtable. (Either it being one function or an actual table so structs could hook into the class finalization method.)As for the bug, it's actually somewhat old. Issue 2834 was filed back in April of 09 - Struct Destructors are not called by the GC, but called on explicit delete. And this is a bug in the spec, not DMD; the only way to run struct destructors from the GC is to add vtables to them or hidden in the GC (i.e. to make them classes).You don't need a vtable, because you don't have inheritance with structs. All you need is a function pointer pointing to the finalization function/method. This plays well with the concept of having type information associated to blocks of memory in the GC, which means (semi)precise heap scanning. So maybe is not a bad idea to make the destructors of structs get called by the GC :)
Jul 10 2010
Jonathan M Davis:It never occurred to me to put a struct on the heap. Obviously, it's not a feature that I use often.Structs are simpler for the compiler, help you produce a smaller program, require less memory for each instance (two words less, not counting the chunk sizez allocated by the GC), the runtime has a bit less things to do to manage them. Putting structs on the heap can be useful if you want to build certain efficient data structures, like certain trees, but you may want to allocate many of them at the same time anyway. One advantage of structs is that they are simpler, so if you have to do simpler things, using a struct you denote that you are doing something simple in your code :-) There's no risk of having virtual functions or inheritance etc if you use structs. Bye, bearophile
Jul 11 2010
Justin Johansson:With care? That doesn't say very much except for possibly an unintended suggestion that the OP is not trying to use care. He is posting because he does care.I probably meant something different. What I meant is just that one of the main purposes of a GC is to free programmers to manually release memory, this makes many other things simpler. If you keep a way to manually delete an object in a GC-based language then the programmer has to use care, to avoid memory leaks, etc. In Python there you can do: del x but it doesn't deallocate the object x, it just decreases by one the reference counts of x (and removes the corresponding name in the current scope), this can lead to the deallocation of x, but it can also happen later. There is no direct command to directly delete an object. So you need less care. Bye, bearophile
Jul 11 2010
bearophile wrote:Justin Johansson:I probably meant something different too and also remiss of me to leave out a few smilies. :-) "has to use care, to avoid memory leaks, etc." Yes and presumably "etc" includes not attempting to delete anything more than once. Cheers JustinWith care? That doesn't say very much except for possibly an unintended suggestion that the OP is not trying to use care. He is posting because he does care.I probably meant something different. What I meant is just that one of the main purposes of a GC is to free programmers to manually release memory, this makes many other things simpler. If you keep a way to manually delete an object in a GC-based language then the programmer has to use care, to avoid memory leaks, etc. In Python there you can do: del x but it doesn't deallocate the object x, it just decreases by one the reference counts of x (and removes the corresponding name in the current scope), this can lead to the deallocation of x, but it can also happen later. There is no direct command to directly delete an object. So you need less care. Bye, bearophile
Jul 12 2010
On Sat, 10 Jul 2010 01:06:39 -0400, Jonathan M Davis <jmdavisprog gmail.com> wrote:I thought that classes always went on the heap and that structs always went on the stack - so allocating structs with new wouldn't work. Also, I thought that delete was deprecated if not outright removed from D. And yet, we have a new bug that Andrei reported about destructors for structs not working correctly when they're allocated with new (and delete is being used to destroy it in the code in the report). http://d.puremagic.com/issues/show_bug.cgi?id=4442 Code from bug report: struct S1{ ~this() { writeln("dtor"); } } void main() { auto a = S1(); auto b = new S1(); delete b; auto c = new S1(); c = null; GC.collect(); } Am I missing something here? TDPL was quite clear that classes were reference types and structs were value types, and here we appear to have a struct used as a reference type. Is this some sort of feature from outside of SafeD, or is it a feature that was supposed to be removed but hasn't yet, or what? I know that TDPL doesn't cover everything and that what dmd does doesn't always match it yet, but from what I understood from reading TDPL, the code above shouldn't compile at all since it's using a struct like a class and is using the supposedy defunct delete operator.structs on the heap are a necessity. Classes are too heavyweight for storing things like graph/tree nodes, one does not need the vtable/lock when one is concerned about performance. Switching from classes to structs on dcollections' nodes saved quite a bit of execution time. The problem I see here is allowing the GC to manage the memory of a struct and having the GC responsible for calling the destructor of something that it can't possibly know the destructor of. Classes have their destructor stored in the vtable, which is how the GC gets at it, the GC has no typeinfo to go on. Even with the proposed precise scanning, I think the GC only stores basic pointer maps, it does not have access to the full TypeInfo. I'd say it's a program error to have a GC allocated struct with a destructor. It should be made a compiler error too. There are ways to have structs stored on the heap and have destructors called on them. Also, the example given in the bug report is very simplistic, just to demonstrate the problem. Does anyone have a good use case for struct dtors being called when allocated by the GC? All of the struct dtors I've seen assume they are stack-allocated. -Steve
Jul 12 2010
On 07/12/2010 07:27 AM, Steven Schveighoffer wrote:Also, the example given in the bug report is very simplistic, just to demonstrate the problem. Does anyone have a good use case for struct dtors being called when allocated by the GC? All of the struct dtors I've seen assume they are stack-allocated.Concrete scenarios of structs ending up on the hap often involve classes that have structs as members, but those do end up being accounted for. Statically disabling new for structs with dtors - that's an interesting idea. Andrei
Jul 12 2010
Andrei Alexandrescu:Statically disabling new for structs with dtors - that's an interesting idea.In this bug report, comment 6, I have asked for a warning, but turning it into an error can work too :-) http://d.puremagic.com/issues/show_bug.cgi?id=2834 Bye, bearophile
Jul 12 2010