www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - is struct delete deterministic? (cf used in Unique)

reply Timothee Cour via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
I'm a little confused about the following:
clear,delete,destroy.
My understanding is that clear is deprecated and delete is planned to be
deprecated, so we should only ever use destroy (which deterministic calls
the destructor but doesn't release memory).

Unique uses delete however in the destructor. Is that still guaranteeing
deterministic destruction when the uniqued element is either a class or
struct? (ie if the destructor has a file handle resource, will it be
deterministically freed?)
Mar 07 2015
next sibling parent reply "weaselcat" <weaselcat gmail.com> writes:
On Saturday, 7 March 2015 at 23:48:39 UTC, Timothee Cour wrote:
 I'm a little confused about the following:
 clear,delete,destroy.
 My understanding is that clear is deprecated and delete is 
 planned to be
 deprecated, so we should only ever use destroy (which 
 deterministic calls
 the destructor but doesn't release memory).

 Unique uses delete however in the destructor. Is that still 
 guaranteeing
 deterministic destruction when the uniqued element is either a 
 class or
 struct? (ie if the destructor has a file handle resource, will 
 it be
 deterministically freed?)
structs are allocated on the stack(unless instantiated with new), and call their destructor when you leave their scope. Unique still guarantees deterministic destruction because it's wrapped around a struct, it's a fairly common 'D idiom' I'd say(i.e, look at how File is implemented - D's runtime and standard library are surprisingly well documented and easy to read.) I'm not sure why Unique uses delete, might just be bitrot.
Mar 07 2015
next sibling parent reply Timothee Cour via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
To clarify, I'm only asking about a struct allocated via new.
Unique!T is wrapped around a struct, but it allocates a struct T via 'new',
so my question still holds: does 'delete t' (where t is a struct allocated
via new) guarantee deterministic destruction?

I'm guessing yes, otherwise Unique would be broken, but where is that
specified in the docs?
And if delete is to be deprecated (according to the docs), what is the
correct way to do that (despite fact that Unique relies on delete).


On Sat, Mar 7, 2015 at 4:02 PM, weaselcat via Digitalmars-d-learn <
digitalmars-d-learn puremagic.com> wrote:

 On Saturday, 7 March 2015 at 23:48:39 UTC, Timothee Cour wrote:

 I'm a little confused about the following:
 clear,delete,destroy.
 My understanding is that clear is deprecated and delete is planned to be
 deprecated, so we should only ever use destroy (which deterministic calls
 the destructor but doesn't release memory).

 Unique uses delete however in the destructor. Is that still guaranteeing
 deterministic destruction when the uniqued element is either a class or
 struct? (ie if the destructor has a file handle resource, will it be
 deterministically freed?)
structs are allocated on the stack(unless instantiated with new), and call their destructor when you leave their scope. Unique still guarantees deterministic destruction because it's wrapped around a struct, it's a fairly common 'D idiom' I'd say(i.e, look at how File is implemented - D's runtime and standard library are surprisingly well documented and easy to read.) I'm not sure why Unique uses delete, might just be bitrot.
Mar 07 2015
parent "weaselcat" <weaselcat gmail.com> writes:
On Sunday, 8 March 2015 at 01:20:57 UTC, Timothee Cour wrote:
 To clarify, I'm only asking about a struct allocated via new.
 Unique!T is wrapped around a struct, but it allocates a struct 
 T via 'new',
 so my question still holds: does 'delete t' (where t is a 
 struct allocated
 via new) guarantee deterministic destruction?

 I'm guessing yes, otherwise Unique would be broken, but where 
 is that
 specified in the docs?
 And if delete is to be deprecated (according to the docs), what 
 is the
 correct way to do that (despite fact that Unique relies on 
 delete).


 On Sat, Mar 7, 2015 at 4:02 PM, weaselcat via 
 Digitalmars-d-learn <
 digitalmars-d-learn puremagic.com> wrote:

 On Saturday, 7 March 2015 at 23:48:39 UTC, Timothee Cour wrote:

 I'm a little confused about the following:
 clear,delete,destroy.
 My understanding is that clear is deprecated and delete is 
 planned to be
 deprecated, so we should only ever use destroy (which 
 deterministic calls
 the destructor but doesn't release memory).

 Unique uses delete however in the destructor. Is that still 
 guaranteeing
 deterministic destruction when the uniqued element is either 
 a class or
 struct? (ie if the destructor has a file handle resource, 
 will it be
 deterministically freed?)
structs are allocated on the stack(unless instantiated with new), and call their destructor when you leave their scope. Unique still guarantees deterministic destruction because it's wrapped around a struct, it's a fairly common 'D idiom' I'd say(i.e, look at how File is implemented - D's runtime and standard library are surprisingly well documented and easy to read.) I'm not sure why Unique uses delete, might just be bitrot.
Unique!T allocates via new, but itself is meant to be allocated on the stack. When it leaves the scope it calls delete on its contents(if they're still valid - i.e, haven't been moved to a different Unique!T) delete guarantees deterministic destruction because structs guarantee deterministic destruction, and Unique!T itself is a struct. http://dlang.org/cpptod.html#raii To answer your questions, 1. Yes, Unique!T guarantees deterministic destruction of T(unless there are bugs I'm unaware of.) 2. It's on the deprecated page. http://dlang.org/deprecate.html#delete
Mar 08 2015
prev sibling parent Jonathan M Davis via Digitalmars-d-learn writes:
On Saturday, March 07, 2015 17:20:49 Timothee Cour via Digitalmars-d-learn
wrote:
 To clarify, I'm only asking about a struct allocated via new.
 Unique!T is wrapped around a struct, but it allocates a struct T via 'new',
 so my question still holds: does 'delete t' (where t is a struct allocated
 via new) guarantee deterministic destruction?

 I'm guessing yes, otherwise Unique would be broken, but where is that
 specified in the docs?
 And if delete is to be deprecated (according to the docs), what is the
 correct way to do that (despite fact that Unique relies on delete).
Yes, delete is deterministic. It's basically the same as what you get in C++ except that it's using the GC heap and therefore is not safe. delete is supposed to have been deprecated but has not been yet (mostly because no one has gotten around to doing it). If you're using the GC heap and want to destroy an object, that's what destroy is for - but it doesn't free the memory, because that's not safe. You can free the memory with core.memory.GC.free, but you have to have destroyed the object first, since free just frees memory. But that's just duplicating what delete does, so it's still unsafe. What's generally considered the correct way to deal with manual memory management involves allocating using C's malloc, constructing via emplace, and then using destroy and C's free to destroy the object and free its memory when you're done. But that's way more of a pain then using new and then delete, which is probably part of why some folks still use delete (in the case of Unique though, I expect that it's just because it's been around a while). Hopefully, the standard allocator stuff will make it as simple as using new and delete though - e.g. something like auto ptr = alloc.make!Myobj(arg1, arg2); alloc.free(ptr); but the standard allocator stuff isn't currently far enough along yet for us to be at that point unfortunately. - Jonathan M Davis
Mar 08 2015
prev sibling next sibling parent Jonathan M Davis via Digitalmars-d-learn writes:
On Sunday, March 08, 2015 04:13:28 Jonathan M Davis via Digitalmars-d-learn
wrote:
 On Saturday, March 07, 2015 17:20:49 Timothee Cour via Digitalmars-d-learn
wrote:
 To clarify, I'm only asking about a struct allocated via new.
 Unique!T is wrapped around a struct, but it allocates a struct T via 'new',
 so my question still holds: does 'delete t' (where t is a struct allocated
 via new) guarantee deterministic destruction?

 I'm guessing yes, otherwise Unique would be broken, but where is that
 specified in the docs?
 And if delete is to be deprecated (according to the docs), what is the
 correct way to do that (despite fact that Unique relies on delete).
Yes, delete is deterministic. It's basically the same as what you get in C++ except that it's using the GC heap and therefore is not safe. delete is supposed to have been deprecated but has not been yet (mostly because no one has gotten around to doing it). If you're using the GC heap and want to destroy an object, that's what destroy is for - but it doesn't free the memory, because that's not safe. You can free the memory with core.memory.GC.free, but you have to have destroyed the object first, since free just frees memory. But that's just duplicating what delete does, so it's still unsafe. What's generally considered the correct way to deal with manual memory management involves allocating using C's malloc, constructing via emplace, and then using destroy and C's free to destroy the object and free its memory when you're done. But that's way more of a pain then using new and then delete, which is probably part of why some folks still use delete (in the case of Unique though, I expect that it's just because it's been around a while). Hopefully, the standard allocator stuff will make it as simple as using new and delete though - e.g. something like auto ptr = alloc.make!Myobj(arg1, arg2); alloc.free(ptr); but the standard allocator stuff isn't currently far enough along yet for us to be at that point unfortunately.
I would point out though that until recently, the GC never ran the destructors for structs on the heap, because it didn't have the type information to do it. So, if you did auto s = new MyStruct; its destructor never ran, even if the GC collected it (which it's not guaranteed to do with any memory). But I don't know if the destructor was run if you expliictly called delete on the pointer to the struct. However, there has recently been work done to make it so that struct destructors on the heap _are_ run when a struct is collected by the GC, so the situation there is improving, and if delete didn't call the destructor before, it probably will with the next release. - Jonathan M Davis
Mar 08 2015
prev sibling next sibling parent Timothee Cour via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On Sun, Mar 8, 2015 at 4:36 AM, Jonathan M Davis via Digitalmars-d-learn <
digitalmars-d-learn puremagic.com> wrote:

 On Sunday, March 08, 2015 04:13:28 Jonathan M Davis via
 Digitalmars-d-learn wrote:
 On Saturday, March 07, 2015 17:20:49 Timothee Cour via
Digitalmars-d-learn wrote:
 To clarify, I'm only asking about a struct allocated via new.
 Unique!T is wrapped around a struct, but it allocates a struct T via
'new',
 so my question still holds: does 'delete t' (where t is a struct
allocated
 via new) guarantee deterministic destruction?

 I'm guessing yes, otherwise Unique would be broken, but where is that
 specified in the docs?
 And if delete is to be deprecated (according to the docs), what is the
 correct way to do that (despite fact that Unique relies on delete).
Yes, delete is deterministic. It's basically the same as what you get in
C++
 except that it's using the GC heap and therefore is not safe. delete is
 supposed to have been deprecated but has not been yet (mostly because no
one
 has gotten around to doing it).

 If you're using the GC heap and want to destroy an object, that's what
 destroy is for - but it doesn't free the memory, because that's not safe.
 You can free the memory with core.memory.GC.free, but you have to have
 destroyed the object first, since free just frees memory. But that's just
 duplicating what delete does, so it's still unsafe.

 What's generally considered the correct way to deal with manual memory
 management involves allocating using C's malloc, constructing via
emplace,
 and then using destroy and C's free to destroy the object and free its
 memory when you're done. But that's way more of a pain then using new and
 then delete, which is probably part of why some folks still use delete
(in
 the case of Unique though, I expect that it's just because it's been
around
 a while). Hopefully, the standard allocator stuff will make it as simple
as
 using new and delete though - e.g. something like

 auto ptr = alloc.make!Myobj(arg1, arg2);
 alloc.free(ptr);

 but the standard allocator stuff isn't currently far enough along yet
for us
 to be at that point unfortunately.
I would point out though that until recently, the GC never ran the destructors for structs on the heap, because it didn't have the type information to do it. So, if you did auto s = new MyStruct; its destructor never ran, even if the GC collected it (which it's not guaranteed to do with any memory). But I don't know if the destructor was run if you expliictly called delete on the pointer to the struct.
Thanks for you answers, however this last sentence worries me. According to it there's no guarantee then?
 However, there has recently been work done to make it so that struct
 destructors on the heap _are_ run when a struct is collected by the GC, so
 the situation there is improving, and if delete didn't call the destructor
 before, it probably will with the next release.

 - Jonathan M Davis
Mar 08 2015
prev sibling parent Jonathan M Davis via Digitalmars-d-learn writes:
On Sunday, March 08, 2015 14:04:52 Timothee Cour via Digitalmars-d-learn wrote:
 On Sun, Mar 8, 2015 at 4:36 AM, Jonathan M Davis via Digitalmars-d-learn <
 I would point out though that until recently, the GC never ran the
 destructors for structs on the heap, because it didn't have the type
 information to do it. So, if you did

 auto s = new MyStruct;

 its destructor never ran, even if the GC collected it (which it's not
 guaranteed to do with any memory). But I don't know if the destructor was
 run if you expliictly called delete on the pointer to the struct.
Thanks for you answers, however this last sentence worries me. According to it there's no guarantee then?
Previously, struct destructors were _never_ run by the GC, because it didn't have the required type information. What I don't know is whether delete called a struct's destructor or not. But if it didn't, then it never did. There was no maybe about it. Either it always did, or it never did. I just don't know which it is, because I haven't really used delete, and I don't recall anyone discussing whether delete had the same problem that the GC does when it runs (I'd guess not, but I'd have to test it). With the upcoming release, however, it's been changed so that struct destructors _do_ get called by the GC, which would presumably make it so that delete calls the struct's destructor if it didn't before. I guess that I can just revert my dmd to an older release and see what happens there (I'm normally sitting on master)... Yeah. delete calls the struct's destructor even though the GC doesn't. And there's nothing non-deterministic about it. The GC isn't guaranteed to collect something (so even with the recent changes with regards to structs, there's still no guarantee that their destructors will be run), but delete is, since you're explicitly telling it to. It was just a question of whether delete had the same problem that the GC did and couldn't run the struct's destructor. But fortunately, that doesn't seem to be the case. - Jonathan M Davis
Mar 08 2015