C++ is the same.
Your code in thread A grabs a pointer. It gets pre-empted by thread B. Thread B deletes the entity. Now thread A has an invalid pointer and is gonna call its method. Bang!
The point of DoWithEntity() is that while it's executing (including the callback), the internal lock is held, guaranteeing that no other thread is manipulating (especially deleting) entities.
Your code in thread A grabs a pointer. It gets pre-empted by thread B. Thread B deletes the entity. Now thread A has an invalid pointer and is gonna call its method. Bang!
The point of DoWithEntity() is that while it's executing (including the callback), the internal lock is held, guaranteeing that no other thread is manipulating (especially deleting) entities.