entt
entt copied to clipboard
Allow storing non-movable objects
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.
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
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.
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?
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.
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. 🤔
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.
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.
Cool. Thanks for the feedback!!