Jump to page: 1 2
Thread overview
class destruction
Sep 09, 2015
Q
Sep 09, 2015
ponce
Sep 09, 2015
Q
Sep 09, 2015
ponce
Sep 09, 2015
Kagamin
Sep 09, 2015
Adam D. Ruppe
Sep 09, 2015
Q
Sep 09, 2015
Q
Sep 09, 2015
Adam D. Ruppe
Sep 09, 2015
Q
Sep 09, 2015
Adam D. Ruppe
Sep 09, 2015
Q
Sep 09, 2015
Adam D. Ruppe
Sep 09, 2015
Meta
September 09, 2015
Hi. I'm playing around with D for a while and I would like to switch. But here is one thing, I need an answer for. In the Docs is mentioned that it is not sure that the DTor of a class is called. But what if I have struct, which holds a C Handle which is destroyed as soon as the struct gets destroyed (more or less like a unique pointer) and I stick this struct into a class (because I strongly need polymorphism)? Can I be sure that the Handle is destroyed as soon as the class is destroyed? Or will the handle leak?
If so there are only two ways that come to mind:
1.  the class holds only a pointer to the struct, which is unsafe since I must guarantee that the struct lives as long as the class
2. the class gets a close/finalize/destroy method (or is called with the built in destroy method), which is a absolute nogo, because it is absolutly sure that this can be forgotten. Besides, we live in 2015 and that is not C where I have to clean my code manually, so this option would be ridiculous :D

I'm gratefull for any answers and ideas.
September 09, 2015
On Wednesday, 9 September 2015 at 07:19:58 UTC, Q wrote:
> Hi. I'm playing around with D for a while and I would like to switch. But here is one thing, I need an answer for. In the Docs is mentioned that it is not sure that the DTor of a class is called. But what if I have struct, which holds a C Handle which is destroyed as soon as the struct gets destroyed (more or less like a unique pointer) and I stick this struct into a class (because I strongly need polymorphism)?

Then you have to make sure the class destruction happens and not rely on the GC.


> Can I be sure that the Handle is destroyed as soon as the class is destroyed?

I think that yes, struct members are destroyed. But you need to make sure the class is destroyed.




> If so there are only two ways that come to mind:
> 1.  the class holds only a pointer to the struct, which is unsafe since I must guarantee that the struct lives as long as the class
> 2. the class gets a close/finalize/destroy method (or is called with the built in destroy method), which is a absolute nogo, because it is absolutly sure that this can be forgotten. Besides, we live in 2015 and that is not C where I have to clean my code manually, so this option would be ridiculous :D
>
> I'm gratefull for any answers and ideas.

I'm using the manual method after much hair-pulling: http://p0nce.github.io/d-idioms/#GC-proof-resource-class

It absolutely is worse than the C++ situation, however with the above pattern leaks will be reported by the GC, which is a nice consolation prize.


Alternatively, stick your class in Unique! / Refcounted! / scoped!




September 09, 2015
On Wednesday, 9 September 2015 at 07:19:58 UTC, Q wrote:
> Besides, we live in 2015 and that is not C where I have to clean my code manually, so this option would be ridiculous :D

The difference is that in C you need to manage POD memory too. Manual management of non-POD resources is a problem of a smaller size, and you can use RAII too.
September 09, 2015
But if others use my code they must think about finalizing the classes? That is very awkward.
I'll take a look at Rust and otherwise I will stick with C++. Thanks for you answer. :)
September 09, 2015
On Wednesday, 9 September 2015 at 07:19:58 UTC, Q wrote:
> Can I be sure that the Handle is destroyed as soon as the class is destroyed?

It will do that automatically.

Like the others said, you won't be sure when the class is destroyed unless you have the user code take ownership of it. (This btw is the same as C++, just in C++ the ownership syntax is a wee bit shorter.)

C++:

class Foo {
  public:
   Foo() { /* acquire */ }
   ~Foo() { /* destroy */ }
};

void useFoo(Foo* foo) { }

// pretend I did the header separation here

int main() {
   Foo foo;
   useFoo(&foo);
   return 0;
}


D:

--
module foo;

class Foo {
   private this() { /* acquire */ }
   ~this() { /* destroy */ }
}

struct OwnedFoo(F) {
	F foo;
	alias foo this;
	~this() {
		.destroy(foo);
	}

	@disable this(this) {}
}

auto create(F, T...)(T t) if(is(F : Foo)) {
    return OwnedFoo!F(new F(t));
}
--

--
module main;
import foo;

void useFoo(Foo foo) {}

void main() {
   auto foo = create!Foo();
}
---


The code is a bit longer since the owned pointer in the standard library isn't exactly what I wanted, but you could use std.typecons.Unique too. (Actually, it does offer a bit more safety in reference escaping than mine. But mine is the closest to C++ default).


The private constructor means it won't let you bypass the owned factory when creating it. A bit extra code in foo means all uses of it will be simple like in main.

Just don't store the reference after it is destroyed, just like you would need to be careful with in C++. Using the library Unique will help you get this right too if you want to learn that.
September 09, 2015
On Wednesday, 9 September 2015 at 14:36:24 UTC, Q wrote:
> But if others use my code they must think about finalizing the classes? That is very awkward.

classes, yes but structs, no.

> I'll take a look at Rust and otherwise I will stick with C++. Thanks for you answer. :)

Well, resource management is only part of the story.
September 09, 2015
On Wednesday, 9 September 2015 at 14:57:26 UTC, Adam D. Ruppe wrote:
> On Wednesday, 9 September 2015 at 07:19:58 UTC, Q wrote:
>> Can I be sure that the Handle is destroyed as soon as the class is destroyed?
>
> It will do that automatically.
>
> Like the others said, you won't be sure when the class is destroyed unless you have the user code take ownership of it. (This btw is the same as C++, just in C++ the ownership syntax is a wee bit shorter.)
>
> C++:
>
> class Foo {
>   public:
>    Foo() { /* acquire */ }
>    ~Foo() { /* destroy */ }
> };
>
> void useFoo(Foo* foo) { }
>
> // pretend I did the header separation here
>
> int main() {
>    Foo foo;
>    useFoo(&foo);
>    return 0;
> }
>
>
> D:
>
> --
> module foo;
>
> class Foo {
>    private this() { /* acquire */ }
>    ~this() { /* destroy */ }
> }
>
> struct OwnedFoo(F) {
> 	F foo;
> 	alias foo this;
> 	~this() {
> 		.destroy(foo);
> 	}
>
> 	@disable this(this) {}
> }
>
> auto create(F, T...)(T t) if(is(F : Foo)) {
>     return OwnedFoo!F(new F(t));
> }
> --
>
> --
> module main;
> import foo;
>
> void useFoo(Foo foo) {}
>
> void main() {
>    auto foo = create!Foo();
> }
> ---
>
>
> The code is a bit longer since the owned pointer in the standard library isn't exactly what I wanted, but you could use std.typecons.Unique too. (Actually, it does offer a bit more safety in reference escaping than mine. But mine is the closest to C++ default).
>
>
> The private constructor means it won't let you bypass the owned factory when creating it. A bit extra code in foo means all uses of it will be simple like in main.
>
> Just don't store the reference after it is destroyed, just like you would need to be careful with in C++. Using the library Unique will help you get this right too if you want to learn that.

But in C++, classes and structs are value types _and_ extendable.There is no pressure to heap allocate a class. Of course, if I do that, I use a unique_ptr (shared_ptr is almost everytime misplaced).
But since D has a GC and (per default) force to heap allocate a class. So IMO the GC should also destroy it, everything else is just awkward. I don't want to hack around in a new language. I think Rust offers my all I want. But thanks for the explanation.

September 09, 2015
And sorry if that sounds rude, I'm just in a hurry. I just think D is not mature enough for serious stuff. :) That is of course only my personal opinion.
September 09, 2015
On Wednesday, 9 September 2015 at 15:10:33 UTC, Q wrote:
> But since D has a GC and (per default) force to heap allocate a class. So IMO the GC should also destroy it, everything else is just awkward.

Well, it *does* by default. If that's what you want, just do it the plain way with simple `new`. It will be destroyed (and any structs inside also destroyed) when the GC gets it.

September 09, 2015
On Wednesday, 9 September 2015 at 15:19:04 UTC, Adam D. Ruppe wrote:
> On Wednesday, 9 September 2015 at 15:10:33 UTC, Q wrote:
>> But since D has a GC and (per default) force to heap allocate a class. So IMO the GC should also destroy it, everything else is just awkward.
>
> Well, it *does* by default. If that's what you want, just do it the plain way with simple `new`. It will be destroyed (and any structs inside also destroyed) when the GC gets it.

I thought that is not guaranteed, according to the docs?
« First   ‹ Prev
1 2