Re: Odd Destructor Behavior

2016-02-08 Thread Matt Elkins via Digitalmars-d-learn

On Monday, 8 February 2016 at 07:31:07 UTC, Daniel Kozak wrote:

Seems to me too, please report it on issues.dlang.org


Reported: https://issues.dlang.org/show_bug.cgi?id=15661



Re: Odd Destructor Behavior

2016-02-07 Thread Daniel Kozak via Digitalmars-d-learn
V Sun, 07 Feb 2016 23:47:39 +
Matt Elkins via Digitalmars-d-learn 
napsáno:

> On Sunday, 7 February 2016 at 23:11:34 UTC, anonymous wrote:
> > On 07.02.2016 23:49, Matt Elkins wrote:  
> >> Oi. Yes, I can, but it is quite a lot of code even if you 
> >> don't count
> >> that it is dependent on OpenGL, GLFW, and gl3n to run to this 
> >> point.
> >> This is why I was disappointed that simpler reproducing cases 
> >> weren't
> >> appearing. I should probably spend more time trying to reduce 
> >> the case
> >> some...  
> >
> > Minimal test cases are great, but if you're not able to get it 
> > down in size, or not willing to, then a larger test case is ok, 
> > too. The problem is clear, and I'd expect reducing it to be 
> > relatively straight-foward (but possibly time-consuming). Just 
> > don't forget about it completely, that would be bad.
> >
> > Also be aware of DustMite, a tool for automatic reduction:
> >
> > https://github.com/CyberShadow/DustMite  
> 
> Turns out it was less hard to reduce than I thought. Maybe it 
> could be taken down some more, too, but this is reasonably small:
> 
> [code]
> import std.stdio;
> 
> struct TextureHandle
> {
>  ~this() {}
> }
> 
> TextureHandle create() {return TextureHandle();}
> 
>   struct TileView
>   {
>   @disable this();
>   @disable this(this);
>   this(TextureHandle a, TextureHandle b) {}
>   ~this() {writeln("HERE2");}
>   }
> 
>   struct View
>   {
>   this(int)
>   {
>   writeln("HERE1a");
>   m_tileView = TileView(create(), create());
>   writeln("HERE1b");
>   }
> 
>   private TileView m_tileView;
> }
> 
> unittest
> {
>  auto v = View(5);
> }
> [/code]
> 
> This yields the following:
> 
> [output]
> HERE1a
> HERE2
> HERE1b
> HERE2
> [/output]
> 
> I would have expected only one "HERE2", the last one. Any of a 
> number of changes cause it to behave in the expected way, 
> including (but probably not limited to):
> * Creating the TextureHandles directly rather than calling 
> create()
> * Using only one argument to TileView's constructor
> * Removing TextureHandle's empty destructor
> 
> That last one especially seems to indicate a bug to me...
Seems to me too, please report it on issues.dlang.org



Re: Odd Destructor Behavior

2016-02-07 Thread Márcio Martins via Digitalmars-d-learn

On Sunday, 7 February 2016 at 21:49:24 UTC, Matt Elkins wrote:
I've been experiencing some odd behavior, where it would appear 
that a struct's destructor is being called before the object's 
lifetime expires. More likely I am misunderstanding something 
about the lifetime rules for structs. I haven't been able to 
reproduce with a particularly minimal example, so I will try to 
explain with my current code:


[...]


The destructor you are seeing is from the assignment:

m_tileView = TileView(...);

This creates a temporary TileView, copies it to m_tileView, and 
then destroys it. I suppose you want to move it instead. You need 
to copy the handles from the temporary into the destination, and 
then clear them out from the temporary to prevent them from being 
released.


std.algorithm has a couple of move() overloads that might be 
useful here.


Odd Destructor Behavior

2016-02-07 Thread Matt Elkins via Digitalmars-d-learn
I've been experiencing some odd behavior, where it would appear 
that a struct's destructor is being called before the object's 
lifetime expires. More likely I am misunderstanding something 
about the lifetime rules for structs. I haven't been able to 
reproduce with a particularly minimal example, so I will try to 
explain with my current code:


I have a struct called "TileView", with the relevant parts 
looking like so:

[code]
struct TileView
{
this(Texture.Handle wallsTexture, Texture.Handle topTexture)
{
// Work happens here, but it doesn't seem to matter to 
reproducing the condition

}

// Destructor added for debugging after seeing odd behavior
~this()
{
import std.stdio;
writeln("HERE2");
}
// ...more implementation that doesn't seem to affect the 
condition...

}
[/code]

An instance of this is stored in another struct called "View", 
with the relevant parts looking like so:

[code]
struct View
{
this(/* irrelevant args here */)
{
writeln("HERE1a");
m_tileView = 
TileView(Texture.create(loadTGA(makeInputStream!FileInputStream("resources/images/grass-topped-clay.tga").handle)), Texture.create(loadTGA(makeInputStream!FileInputStream("resources/images/grass-outlined.tga").handle)));//, Texture.create(loadTGA(makeInputStream!FileInputStream("resources/images/grass-outlined.tga").handle)));

writeln("HERE1b");
}

TileView m_tileView;
// ...more irrelevant implementation...
}
[/code]

The output from the two writelns in View and the one in TileView 
is:

[output]
HERE1a
HERE2
HERE1b
[/output]

So the destructor of TileView is being called during its 
construction. Flow proceeds normally (e.g., no exception is 
thrown), as demonstrated by "HERE1b" being printed. Interestingly 
enough, it all seems to hinge on the second argument to 
TileView's constructor; if I make it on a separate line 
beforehand and pass it in, or if I don't pass in a second 
argument at all, I don't see this behavior. In fact, almost any 
attempt I've made to reduce the problem for illustration causes 
it to vanish, which is unfortunate.


From this non-reduced situation, does anything jump out? Am I 
missing something about struct lifetimes? This is the only place 
I instantiate a TileView.


Thanks!




Re: Odd Destructor Behavior

2016-02-07 Thread Matt Elkins via Digitalmars-d-learn

On Sunday, 7 February 2016 at 22:35:57 UTC, anonymous wrote:

On 07.02.2016 23:07, Márcio Martins wrote:

The destructor you are seeing is from the assignment:

m_tileView = TileView(...);

This creates a temporary TileView, copies it to m_tileView, 
and then
destroys it. I suppose you want to move it instead. You need 
to copy the
handles from the temporary into the destination, and then 
clear them out

from the temporary to prevent them from being released.


I think you're mistaken here. The result of a struct literal is 
usually moved implicitly.


Code:

import std.stdio;

struct S
{
~this() {writeln("dtor");}
}

void main()
{
auto s = S();
writeln("end of main");
}


Output:

end of main
dtor


If there was a copy that's destroyed after the assignment, 
there should be another "dtor" before "end of main".


Yeah...and I just stuck this into TileView:
@disable this();
@disable this(this);

and it compiled just fine. If it created a copy I assume the 
compiler would have choked on that.


Re: Odd Destructor Behavior

2016-02-07 Thread anonymous via Digitalmars-d-learn

On 07.02.2016 22:49, Matt Elkins wrote:

 From this non-reduced situation, does anything jump out? Am I missing
something about struct lifetimes? This is the only place I instantiate a
TileView.


Looks weird. I presume this doesn't happen with simpler constructor 
parameters/arguments, like int instead of Texture.Handle? I don't see 
how the parameter types would make a destructor call appear. Might be a bug.


Can you post the code for Texture, makeInputStream, etc, so that we have 
a full, reproducible test case?


Re: Odd Destructor Behavior

2016-02-07 Thread anonymous via Digitalmars-d-learn

On 07.02.2016 23:07, Márcio Martins wrote:

The destructor you are seeing is from the assignment:

m_tileView = TileView(...);

This creates a temporary TileView, copies it to m_tileView, and then
destroys it. I suppose you want to move it instead. You need to copy the
handles from the temporary into the destination, and then clear them out
from the temporary to prevent them from being released.


I think you're mistaken here. The result of a struct literal is usually 
moved implicitly.


Code:

import std.stdio;

struct S
{
~this() {writeln("dtor");}
}

void main()
{
auto s = S();
writeln("end of main");
}


Output:

end of main
dtor


If there was a copy that's destroyed after the assignment, there should 
be another "dtor" before "end of main".


Re: Odd Destructor Behavior

2016-02-07 Thread Matt Elkins via Digitalmars-d-learn

On Sunday, 7 February 2016 at 22:04:27 UTC, anonymous wrote:

On 07.02.2016 22:49, Matt Elkins wrote:
 From this non-reduced situation, does anything jump out? Am I 
missing
something about struct lifetimes? This is the only place I 
instantiate a

TileView.


Looks weird. I presume this doesn't happen with simpler 
constructor parameters/arguments, like int instead of 
Texture.Handle? I don't see how the parameter types would make 
a destructor call appear. Might be a bug.


Correct; if I switch the second Texture.Handle to an int it 
doesn't happen. Nor if I remove it altogether. Nor if I create 
the Texture.Handle on the line immediately above TileView's 
construction, and then pass in the created Texture.Handle. I also 
didn't understand how the parameters would cause this.


Can you post the code for Texture, makeInputStream, etc, so 
that we have a full, reproducible test case?


Oi. Yes, I can, but it is quite a lot of code even if you don't 
count that it is dependent on OpenGL, GLFW, and gl3n to run to 
this point. This is why I was disappointed that simpler 
reproducing cases weren't appearing. I should probably spend more 
time trying to reduce the case some...


Re: Odd Destructor Behavior

2016-02-07 Thread anonymous via Digitalmars-d-learn

On 07.02.2016 23:49, Matt Elkins wrote:

Oi. Yes, I can, but it is quite a lot of code even if you don't count
that it is dependent on OpenGL, GLFW, and gl3n to run to this point.
This is why I was disappointed that simpler reproducing cases weren't
appearing. I should probably spend more time trying to reduce the case
some...


Minimal test cases are great, but if you're not able to get it down in 
size, or not willing to, then a larger test case is ok, too. The problem 
is clear, and I'd expect reducing it to be relatively straight-foward 
(but possibly time-consuming). Just don't forget about it completely, 
that would be bad.


Also be aware of DustMite, a tool for automatic reduction:

https://github.com/CyberShadow/DustMite


Re: Odd Destructor Behavior

2016-02-07 Thread Matt Elkins via Digitalmars-d-learn

On Sunday, 7 February 2016 at 23:11:34 UTC, anonymous wrote:

On 07.02.2016 23:49, Matt Elkins wrote:
Oi. Yes, I can, but it is quite a lot of code even if you 
don't count
that it is dependent on OpenGL, GLFW, and gl3n to run to this 
point.
This is why I was disappointed that simpler reproducing cases 
weren't
appearing. I should probably spend more time trying to reduce 
the case

some...


Minimal test cases are great, but if you're not able to get it 
down in size, or not willing to, then a larger test case is ok, 
too. The problem is clear, and I'd expect reducing it to be 
relatively straight-foward (but possibly time-consuming). Just 
don't forget about it completely, that would be bad.


Also be aware of DustMite, a tool for automatic reduction:

https://github.com/CyberShadow/DustMite


Turns out it was less hard to reduce than I thought. Maybe it 
could be taken down some more, too, but this is reasonably small:


[code]
import std.stdio;

struct TextureHandle
{
~this() {}
}

TextureHandle create() {return TextureHandle();}

 struct TileView
 {
 @disable this();
 @disable this(this);
 this(TextureHandle a, TextureHandle b) {}
 ~this() {writeln("HERE2");}
 }

 struct View
 {
 this(int)
 {
 writeln("HERE1a");
 m_tileView = TileView(create(), create());
 writeln("HERE1b");
 }

 private TileView m_tileView;
}

unittest
{
auto v = View(5);
}
[/code]

This yields the following:

[output]
HERE1a
HERE2
HERE1b
HERE2
[/output]

I would have expected only one "HERE2", the last one. Any of a 
number of changes cause it to behave in the expected way, 
including (but probably not limited to):
* Creating the TextureHandles directly rather than calling 
create()

* Using only one argument to TileView's constructor
* Removing TextureHandle's empty destructor

That last one especially seems to indicate a bug to me...


Re: Odd Destructor Behavior

2016-02-07 Thread Matt Elkins via Digitalmars-d-learn

Some environment information:
DMD 2.070 32-bit
Windows 7 (64-bit)