Skip to content

Conversation

@Watermelon914
Copy link

@Watermelon914 Watermelon914 commented Nov 15, 2025

The explanation of how the code currently works and why it's a problem:

  • When a component is removed from an entity, it moves from one table to another table. Any component not moved over is overwritten when the last entity in that table is moved to the previous entity's position. For regular types, this calls dtor on them, but for types that don't support non-destructive moves, this just overwrites them. This results in memory leaks if you try to remove a type that only supports non-destructive moves, because the dtor is not properly called.
  • When an entity is deleted and it's not at the end of the table, the last entity of that table is moved into its current location. Regardless of whether the type supports non-destructive moves or not, the memory location is always considered valid and should be move_dtor'd, but for types that don't support non-destructive moves, this doesn't happen. This, again, leads to a memory leak.

To fix this, I've adjusted how dtors get called for types that don't support destruction so that the following is upheld:

  • All types call move_dtor if they are being destructed in a flecs_table_delete call.
  • Types that don't support non-destructive moves do not dtor when moved into during a non-destructive flecs_table_delete call
  • Instead, this dtor happens during flecs_table_move if the type does not support non-destructive moves.

The reason this dtor needs to happen in flecs_table_move is because, while it may be safe to dtor the memory location of a moved object in C++ or C, the same can't be said for Rust. In Rust, a move is essentially a memcpy, except you aren't allowed to dtor or touch the previous values. Therefore, when the flecs_table_delete runs to fill in the space of the moved components, we can't know which components have been moved and which ones need to be dtor'd, so the only safe option is to assume that it is unconstructed memory, and to handle the dtor during the actual move of the entity between tables, unless the entity is being destroyed. In this case, the memory location should always be valid and should therefore be dtor'd.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant