🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

How to use handles

Started by
5 comments, last by kaysik 19 years, 2 months ago
Lately I'm looking into using object handles, however I am getting stuck trying to understand some notions behind the idea of reference-counted objects. I've pretty much been able to register AddRef and Release behaviours and by trial and error I figured out that the first time the object is created within a script, it's reference should be set to 1 - setting it to zero causes premature destruction of the object, followed by another destruction call on a dangling pointer. From what I gather, AddRef and Release are called on construction of the object and on leaving the scope, respectively. Am I correct in assuming that object creation is in itself a reference i.e. should I set it to 1 in the constructor? Also, I'm confused about the notion of assignment. Let's say I define the assignment behaviour, mapping it to the operator= of the object. Should the operator= keep the same refernce count for the copied object? reset it? should assignment be allowed in the first place? or should it return the same object but with an increased reference count?
tIDE Tile Map Editorhttp://tide.codeplex.com
Advertisement
* The constructor should return with one reference already counted.

* Any function that returns a handle should increase the reference counter to account for the returned reference.

* When returning a reference to an object, the reference counter shouldn't be increased. The script engine will do this if a handle to the object is stored.

* Any function that receives a handle by value in a parameter must decrease the reference counter when it is no longer using the handle.

* The assignment operator works on two different objects, thus shouldn't change the reference counter on either of them, but only copy the actual data contained in the argument object.

// Pseudo C++ codeclass Obj{  int refCounter;  int val;};Obj &Obj::operator=(const Obj &other){  // Only copy the other object's contents  val = other.val;  // Return a reference to this object  return *this;}


* The normal assignment operator calls the object's assignment behaviour to copy the value of the right hand object to the left hand object.

// Script codea = b; // The assignment behaviour is called. a and b are different objects.


* The handle assignment operator is used when storing a handle to an object for later use. This will automatically increase the reference count of the object (by means of the ADDREF behaviour).

// Script code@a = @b; // A handle assignment. a and b are now handles to the same object.


I hope that helps explain things for you.

Regards,
Andreas

PS. I will write a few standard classes as add ons that will show exactly how objects are registered.

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

Brilliant! :)

The root of my handle problem was in the assignment operator as a matter of fact. Come to think of it, if object A has N refs and object B has M refs, then the assignment A = B should not alter N or M at all. Reference counting worked nicely when passed in and out of script functions too with a reference count restored as expected.

I also noticed that only the asBEHAVE_CONSTRUCT behaviour is used when asBEHAVE_ADDREF and asBEHAVE_RELEASE are registered - asBEHAVE_DESTRUCT is never called.

Thanks!
tIDE Tile Map Editorhttp://tide.codeplex.com
Worth noting for the benefit of this thread is that handles can be passed in and out of functions using the @ symbol like this:

float GetDistance(Point @p1, Point @p2)
{
...
}

I think it's worth adding to the docs since there is no mention of handles within the context of parameter passing in and out of function calls.

I'm definitely beginning to see the light about handles and ref counting! Wish I figured them out sooner :)

AngelScript rocks!
tIDE Tile Map Editorhttp://tide.codeplex.com
Whats the difference between passing in a handle and a reference? Currently I use references but handles seem like they would be more like what I'm after. Most of the time I never want to copy or even create a new item - just get the handle/ref and use it.

For my game entities have on touch scripts which currently takes a reference to the entity it touched (so say a health pack will take the entity reference and then increase the health count of whatever it touched). Would it better to pass a handle into the function? or is there no reall difference?

Also what about returning a handle from an app function to the script? Is that possible and will it work? I don't think you can do it with references (at least I haven't seen it done anywhere in the docs). If so do I just return a pointer and AS will make the proper conversion into a handle or do I need todo something tricky? I'll test it out later and see see if I can get it to work with blind guesses :P ... wish me luck!

Update: ok I failed. Is it even possible to return a handle or ref from an appfunction to the script? cos i really need it, and I'm thinking it'd be something everyone would use so I'm guessing its in there somewhere - just need help to point me in the right direction!

[Edited by - kaysik on April 2, 2005 6:26:51 AM]
There is a real difference.

Handles

- C++ type is a normal pointer
- The pointer is reference counted
- It can be null
- The pointer to the real object is sent as function parameter
- A little more work is needed by application to maintain reference count
- Application can store received pointer for later use

References

- C++ type is a normal pointer or a C++ reference
- The pointer is not reference counted
- It's guaranteed to point to an object (i.e. not null)
- A reference to a cloned object is passed as function parameter, not the real object
- Application can't store received pointer for later use

Handles are normally more effective, since they don't make extra copies of the objects, they only add a reference count. References make copies of the original object to guarantee that the pointer is valid during the lifetime of the reference.

You should definitely use handles where possible.

Yes, it is possible to return both references and handles from an application function, and it is quite simple.

// Our objectclass Object o;Object *ReturnRef(){  return &o}Object *ReturnHandle(){  // We need to increase the reference   // count for the returned reference  o.AddRef();  return &o}void main(){  ...  engine->RegisterGlobalFunction("object &ReturnRef()", asFUNCTION(ReturnRef), asCALL_CDECL);  engine->RegisterGlobalFunction("object@ ReturnHandle()", asFUNCTION(ReturnHandle), asCALL_CDECL);  ...}


I'm releasing the final version of 2.1.0 today. With it I'm also releasing a new add_on class, asCScriptString. This class shows how the std::string can be wrapped in a contained that allows reference counting to be added so that the scripts can use handles with strings. The asCScriptString class can still be sent by reference without changes to application functions that takes a pointer to a std::string.

You may use this class as an example on how to register application classes with the scripting engine.

Regards,
Andreas



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

Ahh thats fantastic - I'll definatly change all my stuff to handles. A few extra behaviours will be worth it, and its looks pretty simple to add now I get how it all works.

Thanks heaps for you help (and the lib in general).

This topic is closed to new replies.

Advertisement