Using null references

Hi,

I couldn’t find a precise definition of variable in Unity3D so I’m looking for help here.

If I use a variable to store an Object.

Let’s say:

var myVar:myClass = new MyClass();

Then I destroy this object from an other script :

//An other script
myOtherVarReferingToSameObject.Destroy();

Now I can use a boolean cast to check if the object still exists

//First script rest
if(myVar){
  //do things on myVar
}

And here is my question.
If myVar is a reference containing the adress of the object, the boolean test will detect that there is no more a MyClass object at this adress and return false.
But is it possible that if I create an other MyClass object (from an other script again, independently) and if it is store at this adress (which is now released) (few chances I admit) that myVar referes to this new object?

If you prefere my question is :
“Is it totaly secure to destroy an object and use a boolean cast on a variable refering to it to know if this object still exists?”

Thanks

there are various errors:

  1. unless you implemented an explicit class with extend in Javascript its always extended from monobehaviour. Monobehaviour do not support the usage of new, they are meant to be used through AddComponent

  2. Its Destroy() not .Destroy().

  3. after destroying something always set the variable manually to null. That gives you a guaranteed state and removes any guessing.
    it will then remain null till something assigns a new object reference to it

I mention these things to save you quite a bit of time, not for being mean. Especially 3 is a good programming practise you should always follow if you want to save hours of planless bughunting

Thank you for your answer.

I understand setting the variable to null,
but is there a way to know if a component which is refered by a variable has been destroy or not regarding this variable?

I’d like to make something like that:

#pragma strict

class MyComp extends MonoBehaviour{
  function Update(){
    if(!Random.Range(0, 1000)){
      Destroy(this);
    }
  }
}
#pragma strict

class MyClass extends MonoBehaviour{
  var comp:MyComp;

  function Awake(){
    comp = this.AddComponent("MyComp") as MyComp;
  }

  function Update(){
    if(FonctionToCheckIfComponentExist(comp)){
      //Do somethings
    }
  }
}

I can change my architecture, I don’t want an other organisation of my code, just know if this kind of things is possible.

Thanks a lot.

Set the variable reference to null in the line after Destroy and you know it, otherwise you might or might not know it and its not stable your knowledge actually

dreamora, I think the problem is that if you pass a reference and it is destroyed, you have no way to set the original variable to null.

A variable references the object at an address in memory. If it is destroyed from memory, the reference is now bad. Like a shortcut in windows after you uninstall the program it used to point to.

In most cases, you can just check to see if the object is not there using

if(!myObject)
{
    Debug.Log("Its Gone!");
}

If it is possible you can store a new object to the same variable without knowing it (I can’t think of how, but I’m sure it is possible), you might want to try caching the instance ID when you create the GameObject:
file:///C:/Program%20Files/Unity/Editor/Data/Documentation/Documentation/ScriptReference/Object.GetInstanceID.html

I haven’t tries this, but it seems like a straight forward concept. Either the reference is bad or the ID is different. Just check them in that order (I’m guessing the second check would break if || is used?):

if(!myObject)
{
    Debug.Log("Its gone!");
    return;
}
else if(myObject.GetInstanceID != cachedID)
{
    Debug.Log("Its been replaced!");
}

Again, these are just guesses. Let me know if I am right. (Still learning),[/i]

It’s not a pointer, it’s a wrapped pointer. The boolean cast works because the actual pointer in the wrapped pointer is set to 0 (and therefore “if (ptr)” evaluates to false since you essentially test if (ptr != 0).

Since you can’t create a new object at address 0, and since the wrapped pointer will not automagically change to a value other than null you will never accidentally have it pointing to something else.

Heck, I’m pretty sure if you stored the address the reference points to, destroy the object pointed to, create a new one, and move it physically (from C++) to the original address, the wrapped pointer will still evaluate to false. It’s that whole managed memory thing.

I’d love to know if I’m wrong, it would kill my believe in wrapped pointers though - admitted I am not a C# coder, but a C coder.

Kaj
ps. Wow, forum speed is getting pretty unusable.

The objects that can be removed with Destroy (ie, the Object class and its children) implement a bit of trickery behind the scenes so that null references will be returned if you try to use a reference to an object that has been destroyed. You can also test against the null value correctly.

I think you should add these rules of references to the documentation of Object.Destroy. (think it is an important part of the engine)

Good suggestion! I’ve passed it on to our technical writer for inclusion in the next update of the docs.

It is not possible to store a new object in an eixstingly stored object because of the way Unity overrides the null comparison, and the way the Garbage Collector works.

The Garbage Collector only frees that location once no references point to it. Even if that reference returns the Unity error it is still returning that Object, it’s just that that Object is designed to return a special error message.

This also means that you can check if the object equals null, but only once you explicitly set it to null will it actually be destroyed in memory(or rather the garbage collector will get it next collect and it cannot be accessed until then).

This also means that you can do one of the stranger things I have seen in code

void Start()
	{
		StartCoroutine(coroutineSample());
	}
	
	IEnumerator coroutineSample
	{
		while(this != null)
		{
			// Do Something
			yield return 0;	
		}
	}

And due to operator overloading on the part of Unity that will not return a null reference and will allow you to run a Coroutine from a different Monobehaviour until the current MonoBehaviour is destroyed. Don’t ask my why you would use this instead of just running the Coroutine from the current Behaviour, but it’s odd that it is even possible to check if you do not exist.

In short, GameObject == null will return true when it is flagged for deletion but it is not actually removed from memory. It will only be removed from memory once all existing references to it are explicitly set to null, and not just compared to null.

Just to clarify: …AND once the GC has run and decided to free the object. The GC is non-deterministic, setting all references to null won’t make an object suddenly disappear from memory.

Yeah, I mentioned it in circle brackets above that that the GC has to run, probably should have added it there too.

Exception are Unity Assets
There you use DestroyImmediate and it will be gone rather soon (next GC run)