entt icon indicating copy to clipboard operation
entt copied to clipboard

Allow storing non-movable objects

Open cmakshin opened this issue 1 year ago • 5 comments

Neither insertion nor in-place deletion move objects but currently all component types have to be movable due to https://github.com/skypjack/entt/blob/0d67020ece3d42e6faefe09e456f6ea68135c0f1/src/entt/entity/storage.hpp#L235

An obvious workaround is to allocate such objects by other methods (std::make_unique, pools, etc.) and put pointers into components but it's less efficient and/or more error-prone.

As a proof of concept I tried to remove that line and disable moves in entt::basic_storage::swap_at(), entt::basic_storage::move_element() and entt::basic_storage::swap_and_pop() with code like

if constexpr(std::is_move_assignable_v<Type>) {
    // ...
} else {
    ENTT_ASSERT(!"The type is not move assignable");
}

With these changes creation and deletion of non-movable components worked just fine and in this case more complex operations like sorting don't make sense anyway.

cmakshin avatar Jun 29 '22 00:06 cmakshin

I think perhaps non moveable components should be allowed when stable pointers are requested, since in those cases moving is avoided to maintain pointer stability

danielytics avatar Jul 01 '22 10:07 danielytics

More or less. In fact, you can compact the storage. However, as long as the type is at least copyable, it works as well. The challenge is with non-copyable and non-movable types. In this case, we should problably give up or assert, dunno.

skypjack avatar Jul 01 '22 12:07 skypjack

Wait a moment. Non-movable types are already supported out of the box. In fact, is_move_constructible_v and is_move_assignable_v are true for non-movable types that are copyable.

Does the problem arise when the move constructor and operator are explicitly deleted? In this case, I think that removing the static_assert is actually all we need to make it work. Whenever you see a call to std::move, it translates to a copy under the hood because of how C++ works.

The only case in which this would break is for a type that isn't copyable nor movable. I wonder if supporting this kind of types is worth it though. Is it your use case?

skypjack avatar Jul 04 '22 15:07 skypjack

Yes, in my case the type is derived from a class defined and used by a third-party library. It is not movable due to non-trivial base class' destructor and copies are technically possible but would require special care to avoid dangling pointers in other parts of that library so I decided to be on the safe side by explicitly deleting copy constructor and operator.

In this case removing the static_assert is not enough because entt::basic_sparse_set uses virtual methods and runtime selection of the deletion mode so the compiler has to generate both moving and non-moving operations even if some of them are never actually used.

The problem is not critical and can be easily circumvented by defining copy/move constructor and operator with always-failing assertions like the one shown in my original message.

cmakshin avatar Jul 04 '22 23:07 cmakshin

I see, yeah. So, the problem isn't about non-movable objects (this is easy solved and I'll do). It's about non-movable and non-copyable types. Slightly more complex but still feasible with a couple of asserts here and there probably. 🤔

skypjack avatar Jul 05 '22 09:07 skypjack

Is there any chance that you can test branch wip? I've just pushed a bunch of changes that adds support to non-movable types among the other things. It would be great if you could confirm that it works as expected. Thanks.

skypjack avatar Aug 03 '22 08:08 skypjack

Hi. I apologize for the long silence but I've tested your changes with a non-copyable-non-movable (i.e. explicitly deleted copy and move constructors and operators) component type and everything is fine.

cmakshin avatar Aug 29 '22 00:08 cmakshin

Cool. Thanks for the feedback!!

skypjack avatar Aug 29 '22 06:08 skypjack