Native Collection's IsCreated controversy
Some people suggest to stop using IsCreated because it is poorly implemented and very dangerous.If you're doing Jobs and maybe ECS, you'll find yourself using Unity's Collections package, which contains NativeArray, and other types of special data structures.
Native Collections are created using Allocators that reserve memory in different ways and, in general, if it's Allocator.TempJob and specially with Allocator.Persistent, you have to eventually call NativeXXX.Dispose(). After that, IsCreated will return false from now on...
What's the controversy?
But people claim that it can be dangerous and problematic to call that. You get unexpected results, exceptions. This happens if the call to Dispose() is done somewhere else. But specifically when you don't realize you passed the Native Collection by value.
Value or Reference
In C# (and many other languages) you can pass variables by value (creating a copy of its contents) and by reference (which doesn't make a copy and modifies the stuff that comes from outside).
Well. In C# that's not that explicit, just like in C++. If you pass an INT to a method it is copied, it's a value type. If you pass a class instance, it is passed by reference by default. That's why you have "ref" that you can add before the type of the parameter in the function signature (top of the method declaration). Ref forces it to pass by reference.
To pass the integer by reference do it this way:
void myMethod (ref int i) { i ++; }
If you change i, it will be changed also outside the method.
What are Native Arrays?
A NativeArray is a struct which essentially has:
- Length
- A pointer to the start of the data
What does IsCreated do?
It checks it the pointer is null or not. Just that!
Dispose()
What happens when you pass a NativeArray to a function without ref?
Structs are by default passed by value. So what we copy is length and the pointer. All instances of the pointer look at the same data.
When you call Dispose() on the place where you passed the Array,
- Clears memory of the pointer
- Sets the length to 0
- Sets that pointer to null
When you call IsCreated, it will return False for this instance, because the pointer is null now.
But other instances didn't set that pointer to null. If you ask if IsCreated it will return true! And so if you try to access the data, you'll get an unexpected result or exception. The data you're accessing has been disposed by the other instance, but you don't know about it.
So that's the controversy.
My suggestion?. It's not that these are poorly implemented, IsCreated is just a simple check, but the same problem could happen with the length and such... so you have to be aware that these collections are structs, that they are copied and that you should better pass it as reference always. So that if you call Dispose() somewhere else you are actually doing all the process inside the original instance.