Advertisement

Object handles

Started by August 10, 2007 11:10 AM
3 comments, last by derefed 17 years, 3 months ago
Having a problem getting object handles to work. I want to keep a (more or less) global TimerCollection, with which I can create new Timers and retrieve handles to them in the script to manipulate. I've added ADDREF and RELEASE behavior to the Timer class, as well as a CONSTRUCT behavior. I haven't added a destructor for it, as the class doesn't have a destructor anyway. The TimerCollection keeps a vector of Timers. When you call Make_Timer(), it creates a new Timer with the name you supply. Get_Timer() returns a reference to a Timer in the vector. Here's the code that registers the important stuff:

   r = engine->RegisterObjectType("Timer", sizeof(Timer), asOBJ_CLASS); assert (r >= 0);
   r = engine->RegisterObjectMethod("Timer", "const string& Get_Name()", asMETHOD(Timer,Get_Name), asCALL_THISCALL); assert (r >= 0);
   r = engine->RegisterObjectMethod("Timer", "bool Is_Active()", asMETHOD(Timer,Is_Active), asCALL_THISCALL); assert (r >= 0);
   r = engine->RegisterObjectMethod("Timer", "void Set_Active(bool)", asMETHOD(Timer,Set_Active), asCALL_THISCALL); assert (r >= 0);
   r = engine->RegisterObjectBehaviour("Timer", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Timer_Cons), asCALL_CDECL_OBJLAST); assert (r >= 0);
   r = engine->RegisterObjectBehaviour("Timer", asBEHAVE_ADDREF, "void f()", asMETHOD(Timer,AddRef), asCALL_THISCALL); assert (r >= 0);
   r = engine->RegisterObjectBehaviour("Timer", asBEHAVE_RELEASE, "void f()", asMETHOD(Timer,Release), asCALL_THISCALL); assert (r >= 0);

   r = engine->RegisterObjectType("TimerCollection", sizeof(TimerCollection), asOBJ_CLASS); assert (r >= 0);
   r = engine->RegisterObjectMethod("TimerCollection", "void Make_Timer(const string &in)", asMETHOD(TimerCollection,Make_Timer), asCALL_THISCALL); assert (r >= 0);
   r = engine->RegisterObjectMethod("TimerCollection", "Timer@ Get_Timer(const string &in)", asMETHOD(TimerCollection,Get_Timer), asCALL_THISCALL); assert (r >= 0);
   r = engine->RegisterGlobalProperty("TimerCollection timers", &timers); assert (r >= 0);

Here's the reference counting code:

void Timer::Release()
{
   if (--refCount == 0)
      delete this;
}

void Timer::AddRef()
{
   ++refCount;
}

Timer::Timer()
{
   startTicks = 0;
   pausedTicks = 0;
   running = false;
   paused = false;
   
   refCount = 1;
}

Here's the code for Get_Timer():

Timer& TimerCollection::Get_Timer(const string &name)
{
   // search for it
   for (vector<Timer>::iterator i = timers.begin(); i != timers.end(); ++i)
   {
      if (i->Get_Name().compare(name) == 0)
      {
         // found it!
         return *i;
      }
   }
   
   // didn't find it
   return null_timer;
}

And finally, here's the line of script that throws a debug assertion failure:

Timer @t3 = timers.Get_Timer("t3");

If you register the function to return a handle, you must increment the reference counter for the handle being returned. And a null handle, is returned as a null pointer, so have your C++ function return a pointer rather than a reference, if you want to be able to return a null handle.

Timer *TimerCollection::Get_Timer(const string &name){   // search for it   for (vector<Timer>::iterator i = timers.begin(); i != timers.end(); ++i)   {      if (i->Get_Name().compare(name) == 0)      {         // found it!         i->AddRef();         return &*i;      }   }      // didn't find it   return 0;}


What assertion failure are you getting?

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
I've changed my function to call AddRef() on the Timer before returning it (I didn't at first because I assumed that AS would be taking care of that); however, I'm still having it return a reference, because I would think that returning a pointer to an object in a vector would be risky, esp. when the vector is resized. I have most returnable objects derive from the Object class, which has a bool variable "active". If active is false, it means the same thing as a NULL pointer to my program, or in other words, the object wasn't found.

Can this still work with references instead of pointers, or must object handles use pointers? Also, the debug assertion failure was this:

File: dbgdel.cpp
Line: 52
Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
Quote:
I'm still having it return a reference, because I would think that returning a pointer to an object in a vector would be risky, esp. when the vector is resized


A pointer or a reference is the same thing in this regard, because AngelScript will still use the reference as if it was a pointer. In fact, you should know that a reference in C++ is in reality a pointer, it only has a different syntax for accessing the value.

If null_timer is an object instance, then you must increment it's reference counter as well.

You're probably getting the debug assertion because AngelScript is calling Release on the handle you gave it, which in turn tries to delete the object from the heap, but the object wasn't allocated on the heap with a new.

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! Makes perfect sense... both to me and my compiler.

Thanks once again, WitchLord =)

This topic is closed to new replies.

Advertisement