AngelScript

Registering a reference type

The basic reference type should be registered with the following behaviours: asBEHAVE_FACTORY, asBEHAVE_ADDREF, and asBEHAVE_RELEASE.

// Registering the reference type
r = engine->RegisterObjectType("ref", 0, asOBJ_REF); assert( r >= 0 );

See Also
  The any add-on for an example of a reference type.
  Garbage collected objects, Class hierarchies, Registering a scoped reference type, and Registering a single-reference type for more advanced types.

# Factory function

The factory function is the one that AngelScript will use to instanciate objects of this type when a variable is declared. It is responsible for allocating and initializing the object memory.

The default factory function doesn't take any parameters and should return an object handle for the new object. Make sure the object's reference counter is accounting for the reference being returned by the factory function, so that the object is properly released when all references to it are removed.

CRef::CRef()
{
// Let the constructor initialize the reference counter to 1
refCount = 1;
}
CRef *Ref_Factory()
{
// The class constructor is initializing the reference counter to 1
return new CRef();
}
// Registering the factory behaviour
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_FACTORY, "ref@ f()", asFUNCTION(Ref_Factory), asCALL_CDECL); assert( r >= 0 );

You may also register factory functions that take parameters, which may then be used when initializing the object.

The factory function must be registered as a global function, but can be implemented as a static class method, common global function, or a global function following the generic calling convention.

# Addref and release behaviours

void CRef::Addref()
{
// Increase the reference counter
refCount++;
}
void CRef::Release()
{
// Decrease ref count and delete if it reaches 0
if( --refCount == 0 )
delete this;
}
// Registering the addref/release behaviours
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_ADDREF, "void f()", asMETHOD(CRef,AddRef), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_RELEASE, "void f()", asMETHOD(CRef,Release), asCALL_THISCALL); assert( r >= 0 );

If the instances of this object will be shared between multiple threads, remember to guarantee that the reference counter is thread safe by making the increments and decrements with atomic instructions.

See Also
  Multithreading

# Reference types without reference counting

If the application provides its own memory management that isn't based on reference counting, then it is possible to register the type without the addref and release behaviours if the flag, asOBJ_NOCOUNT is informed in the call to RegisterObjectType, i.e.

// Registering the reference type
r = engine->RegisterObjectType("ref", 0, asOBJ_REF | asOBJ_NOCOUNT); assert( r >= 0 );

Without the addref and release behaviours the application must be careful to not destroy any objects that may potentially still be referenced by the script engine, e.g. in a global variable, or other location.

Unless the objects are guaranteed to stay alive as long as the script engine is instanciated, you may want to consider disabling global variables with engine property asEP_DISALLOW_GLOBAL_VARS. This will make it much easier for the application to know where references to the objects are kept. An alternative to disabling all global variables, is to selectively disallow only the global variables, that can eventually store a reference to the object type. This can be done by enumerating the compiled global variables after script has been built and giving an error to the user incase he includes a variable he shouldn't.

# Registering an uninstanciable reference type

Sometimes it may be useful to register types that cannot be instanciated by the scripts, yet can be interacted with. You can do this by registering the type as a normal reference type, but omit the registration of the factory behaviour. You can later register global properties, or functions that allow the scripts to access objects created by the application via object handles.

This would be used when the application has a limited number of objects available and doesn't want to create new ones. For example singletons, or pooled objects.