Unittests pass, and then an invalid memory operation happens after?

Liam McGillivray yoshi.pit.link.mario at gmail.com
Thu Mar 28 03:56:10 UTC 2024


On Wednesday, 27 March 2024 at 22:14:16 UTC, H. S. Teoh wrote:
> What's the definition of this.map, this.faction, and 
> this.currentTile?

As was said, and can be found on the linked repository, they are 
references to class objects.

On Thursday, 28 March 2024 at 01:47:27 UTC, Steven Schveighoffer 
wrote:
> On Wednesday, 27 March 2024 at 21:43:48 UTC, Liam McGillivray 
> wrote:
>> `Unit` destructor:
>> ```
>>     ~this() {
>>         this.alive = false;
>>         if (this.map !is null) this.map.removeUnit(this);
>>         if (this.faction !is null) 
>> this.faction.removeUnit(this);
>>         if (this.currentTile !is null) 
>> this.currentTile.occupant = null;
>>     }
>> ```
>
> The GC does not guarantee destructor order. So this code is not 
> valid -- e.g. you can't count on `map` to be a valid object at 
> this point.

Well, this was originally done so that when I explicitly call 
`destroy` on a Unit object (which happens in-game) it will delete 
all references to itself.

Do you think it's better for me to move this code to a `die` 
function that I can call instead, which will then call for it's 
own destruction after running those function calls?

> The *only* thing you should be doing in a destructor is freeing 
> non-GC resources.
>
>> I read that the garbage collector *sometimes* but not *always* 
>> calls destructors on deletion, which sounds crazy to me.
>
> The GC is not guaranteed to delete memory or run destructors. 
> In the current implementation, it will destroy everything at 
> the end of the program that was allocated using the GC, but the 
> language does not guarantee this.

What's strange is that even if I explicitly call `destroy` for 
the only two objects at the end of the last unittest, it still 
happens. I assumed that each unittest was like it's own program, 
but I suppose not. It's deleting objects from an earlier 
unittest, right?

I may be now starting to see why the use of a garbage collector 
is such a point of contention for D. Not being able to predict 
how the garbage collection process will happen seems like a major 
problem.

> As mentioned, GCs do not work this way -- you do not need to 
> worry about cascading removal of anything.

Wanting to avoid the GC pauses that I hear about, I was trying to 
optimize object deletion so that the GC doesn't have to look for 
every object individually. It sounds like what I'm hearing is 
that I should just leave everything to the GC. While I can do 
this without really hurting the performance of my program (for 
now), I don't like this.

I hope that solving the unpredictable destruction pattern is a 
priority for the developers of the language. This problem in my 
program wouldn't be happening if either *all* of the objects had 
their destructors called or *none* of them did.

Anyway, I suppose I'll have to experiment with either manually 
destroying every object at the end of every unittest, or just 
leaving more to the GC. Maybe I'll make a separate `die` function 
for the units, if you think it's a good idea.

Also, check your Github notifications. I have something for you.



More information about the Digitalmars-d-learn mailing list