entt
entt copied to clipboard
basic_sparse_set - assure_at_least Assertion `elem == null' failed.
Hello,
how can this assertion happen?
The call looks like:
reg.emplace_or_replace<Component>(entity, SOME_STATIC_STRING);
Which leads to the assert on:
The component to add looks like:
struct Component
{
QString str;
};
A check with reg.valid on the entity did not return any error (and a couple of time the call works without causing the assert).
Not sure what else to check, as far as I can tell, the entity was also not deleted...
entt version:
#define ENTT_VERSION_MAJOR 3
#define ENTT_VERSION_MINOR 11
#define ENTT_VERSION_PATCH 0
Thanks in advance.
Do you have a repro? At first glance, it looks like you're assigning the same component to the same entity twice.
Unfortunately not, but would that cause any problems? I thought emplace_or_replace would ignore the case when there is a component already present...
if(!reg.try_get<Component>(ent))
{
reg.emplace_or_replace<int>(ent, 123);
reg.emplace_or_replace<Component>(ent, SOME_STATIC_STRING);
}
ok, really strange, that crashes still on the Component emplace call, so now I'm out of ideas...
It can be anything. A multi-threading issue, a call on a moved-from registry, whatever. I can't help much without a repro, really.
Hmm, I already checked that, only one thread calls the code and there is no move done (singleton registry)... Is there any reason why the assert is not in this code: https://github.com/skypjack/entt/blob/f2c417435c021b6bd2e426ffd9d1fc116b804146/src/entt/entity/sparse_set.hpp#L189 But in here: https://raw.githubusercontent.com/skypjack/entt/f2c417435c021b6bd2e426ffd9d1fc116b804146/single_include/entt/entt.hpp Without knowing the internal structure in detail, its hard to understand what this assert is causing, to me the code looks like the assert should actually not happen. Can maybe someone explain in what condition this assert is hit? I guess that would help to check if/how the calling code messes something up.
The assert tells you that the slot is already taken. It means that the set already contains the entity. That's all.
The component type doesn't really matter too, it would be the same for a storage<void> type.
Without a repro it's nearly impossible to tell why you're hitting this though. I'm sorry. You're the only one that can debug it.
I agree that the assert should not happen. It's there to save all users (including me) from their own mistakes. 🙂
Are shared libraries involved?
The assert tells you that the slot is already taken. It means that the set already contains the entity. That's all. The component type doesn't really matter too, it would be the same for a
storage<void>type. Without a repro it's nearly impossible to tell why you're hitting this though. I'm sorry. You're the only one that can debug it. I agree that the assert should not happen. It's there to save all users (including me) from their own mistakes. 🙂
Hmm, strange that this (entity already in the set) matters on a call of emplace_or_replace (-> if so, do a replace?), but there will be reasons I guess XD
Are shared libraries involved?
Yes. Maybe smth leaks into the registry, that the is the last thing I can think of. Thanks.
Try looking into EnTT documentation about working with shared libraries. If you don't do things properly, then each shared library will have it's own set of identifiers for components and stuff.
Try looking into EnTT documentation about working with shared libraries. If you don't do things properly, then each shared library will have it's own set of identifiers for components and stuff.
Thanks for pointing it out, do you mean in the wiki? Could you please provide a link to what you are referring to?
https://github.com/skypjack/entt/wiki/Push-EnTT-across-boundaries
Just FYI, I had the exact same assertion when emplacing a component after previously accessing the same type of component from a deleted entity (Which of course is wrong).
Something like this
reg.emplace<Transform>(e, {});
reg.destroy(e);
reg.get_or_emplace<Transform>(e); // bad
// ...
auto e2 = reg.create();
reg.get_or_emplace<Transform>(e2); // triggers assert
Just FYI, I had the exact same assertion when emplacing a component after previously accessing the same type of component from a deleted entity (Which of course is wrong).
Something like this
reg.emplace<Transform>(e, {}); reg.destroy(e); reg.get_or_emplace<Transform>(e); // bad // ... auto e2 = reg.create(); reg.get_or_emplace<Transform>(e2); // triggers assert
N1. That looks like the issue 👍🏻😀
Wait a moment. In this case, EnTT should throw an assert to you. Did you disable them?
Wait a moment. In this case, EnTT should throw an assert to you. Did you disable them?
No I did not. I was confused about that as well.
EDIT: Can you try this?
entt::registry reg;
auto e = reg.create();
reg.emplace<int>(e);
reg.destroy(e);
reg.get_or_emplace<int>(e); // no assert
auto e2 = reg.create();
reg.emplace<int>(e2); // assert
Oh, I see. The set doesn't contain the entity and therefore you can emplace the element.
However, the second emplace finds the slot occupied and triggers an error. Makes sense.
In theory, I can add a valid(entt) check within the get_or_emplace function but nothing prevents you from accessing the storage as in .storage<int>() and getting around the check if you like.
Well an assertion at the point of error would have saved me some time in this case. I think it's worth adding even if it doesn't work when accessing the storage directly.
It's your baby :), you can judge best, but asserting asap sounds good to me.
Mmm, ok, let's reopen the issue as feature request then. We can add the checks back in place with the next release. 👍
Checks available on the wip branch (with non-regression tests too).
They'll be part of the next release. Thanks for pointing this out. 👍