Advertisement

Difference between object handles/references

Started by March 09, 2016 07:57 PM
5 comments, last by Budskii 8 years, 8 months ago

Ok, so I've just start using Angelscript recently and absolutely love it. Have a question on something i'm confused about

I've registered an object like this:

r = scriptEngine->RegisterObjectType("CTimer", 0, asOBJ_REF); assert( r >= 0 );
r = scriptEngine->RegisterObjectBehaviour("CTimer", asBEHAVE_ADDREF, "void f()", asMETHOD(CTimer, AddRef), asCALL_THISCALL); assert( r >= 0 );
r = scriptEngine->RegisterObjectBehaviour("CTimer", asBEHAVE_RELEASE, "void f()", asMETHOD(CTimer, ReleaseRef), asCALL_THISCALL); assert( r >= 0 );
r = scriptEngine->RegisterObjectBehaviour("CTimer", asBEHAVE_FACTORY, "CTimer@ f()", asFUNCTION(Scr_CTimer_Factory), asCALL_CDECL); assert( r >= 0 );
I can't seem to find anything in documentation or forums about the differences between references and object handles. From what I understand from a C++/memory perspective is that they are both pointers. I also understand that a reference cannot be null and a object handle can be. Apart from that what is the difference between them say when i'm using CTimer object.
I've switched all the &'s to @ and everything works just fine.

The difference between a reference and handle in AngelScript is pretty much the same as the difference between a reference and a pointer in C++.

You already stated one of the differences: "I also understand that a reference cannot be null and a object handle can be".

Another difference is that a reference cannot be reassigned to point to a different object while an handle can be.

When registering functions with AngelScript you'll have to be careful with the choice of reference versus handle due to the reference counting. When registering the function as returning a reference, the C++ function must not increment the ref counter of the object, but when registering the function as returning a handle, the C++ function must increment the ref counter of the object (or use auto handles to tell AngelScript to do that for you). If you don't do this correctly you may end up with memory leaks, or crashes due to the objects being freed too early.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Advertisement

The difference between a reference and handle in AngelScript is pretty much the same as the difference between a reference and a pointer in C++.

You already stated one of the differences: "I also understand that a reference cannot be null and a object handle can be".

Another difference is that a reference cannot be reassigned to point to a different object while an handle can be.

When registering functions with AngelScript you'll have to be careful with the choice of reference versus handle due to the reference counting. When registering the function as returning a reference, the C++ function must not increment the ref counter of the object, but when registering the function as returning a handle, the C++ function must increment the ref counter of the object (or use auto handles to tell AngelScript to do that for you). If you don't do this correctly you may end up with memory leaks, or crashes due to the objects being freed too early.

Thank you for the reply.

I registered a callback like this:


r = scriptEngine->RegisterFuncdef("void CTimerCallback(CTimer@)");

In a script I made this function:


void DoRandomStuff(CTimer@ timer)
{
Print("Well this is great\n");
}
I made a new CTimer in C++ and initliazed its refCount to 1 and then called DoRandomStuff() from C++ but this did not reduce the refCount. I'm assuming refCount is supposed to be reduced by the function caller and not the function called?
This will be a bit more work I guess, you would have to call C++ script functions and after it is done executing releaseRef() yourself manually
Also, a question regarding this script;


CTimer timer;
CTimer@ timer_handle = @timer;


void DoRandomStuff(CTimer@ timer)
{
Print("Well this is great\n");
}

that all makes sense, but if you need to pass that handle (timer_handle) which was declared to be a handle onto another function do you need to use @?

so should it be:


DoRandomStuff(timer_handle);

or


DoRandomStuff(@timer_handle);

They both work and script runs fine but I'm wondering if there is any different between the two?

Earlier I said "I'm assuming refCount is supposed to be reduced by the function caller and not the function called?"

I decided to test this out in a script, I added logging AddRef() ReleaseRef() and Constructor functions in the CTimer class

I tested it with this script:


void main()
{
	CTimer Timer;
	Timer.start();
	Sleep(50);
	Timer.stop();
	Print("Stopped timer\n");

	CTimer@ timer_handle = @Timer;
	PrintElapsedTime(timer_handle);
	Print("Returned to main()\n");
}

void PrintElapsedTime(CTimer@ timer)
{
	Print("PrintElapsedTime() called\n");
	Print("Time elapsed: " + timer.milliseconds() + "\n");
}

3hoehEw.png

As you can see ReleaseRef() was called in PrintElapsedTime() for then handle passed in parameter

But this doesn't happen when you call a script function which takes in a handle as parameter from C++ application

Actually, script not calling ReleaseRef() might be an error from my part, doing some more testing, will update post

EDIT: it appears the script calls AddRef() and also ReleaseRef() when it is called from C++ that would explain why from my earlier test memory was never freed and so I thought ReleaseRef() wasn't called.

Create object in C++ (ref=1) -> call script function (ref += 1 -> ref = 2) -> finish script function (ref -=1 -> ref = 1)

I'd have to initliase the object with ref=0 from C++ and then that way it would delete in script, but it is supposed to be initliased to ref=1


They both work and script runs fine but I'm wondering if there is any different between the two?

There is no difference in this case. The compiler sees that the function expects a handle and thus implicitly adds the @ to argument. Whenever there is no doubt that a handle is desired, the compiler will do this for you so for the most part you will not have to type @ all the time.


I'd have to initliase the object with ref=0 from C++ and then that way it would delete in script, but it is supposed to be initliased to ref=1

Objects should be initialized with refcount = 1, to reflect that the one that creates the object holds a reference to the object.

When passing a newly created object to the script function you shouldn't increment the refcount further unless the application is also holding on to a reference to the object.

By the way, how are you passing the handle to the script function? Depending on the method you use on the asIScriptContext to set the argument, the refcount will be automatically incremented for you.

asIScriptContext::SetArgAddress will not increment the refCount

asIScriptContext::SetArgObject will increment the refCount (if the script function expects a handle)

asIScriptContext::GetAddressOfArg will not increment the refCount

The script function will always call release on the handles it receives as parameters, the script doesn't know if the function is called from C++ or from another script function. You may see additional calls to addref/release depending on what the script does with the handle.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Advertisement

Ah okay thanks. I was using SetArgObject(), that would explain the increment of ref counter. I've switched it to SetArgAddress and it works fine now

This topic is closed to new replies.

Advertisement