// Registering the garbage collected reference type r = engine->RegisterObjectType("ref", 0, asOBJ_REF | asOBJ_GC); assert( r >= 0 );
The difference between the garbage collected and non-garbage collected types is in the addref and release behaviours, the class constructor, and the extra support behaviours.
The process of determining the dead objects uses the first for of the behaviours below, while the destruction of the objects is done by forcing the release of the object's references.
void CGCRef::SetGCFlag() { // Set the gc flag as the high bit in the reference counter refCount |= 0x80000000; } bool CGCRef::GetGCFlag() { // Return the gc flag return (refCount & 0x80000000) ? true : false; } int CGCRef::GetRefCount() { // Return the reference count, without the gc flag return (refCount & 0x7FFFFFFF); } void CGCRef::EnumReferences() { // Call the engine::GCEnumCallback for all references to other objects held engine->GCEnumCallback(myref); } void CGCRef::ReleaseAllReferences() { // When we receive this call, we are as good as dead, but // the garbage collector will still hold a references to us, so we // cannot just delete ourself yet. Just free all references to other // objects that we hold if( myref ) { myref->Release(); myref = 0; } } // Register the GC support behaviours r = engine->RegisterObjectBehaviour("gc", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CGCRef,SetGCFlag), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("gc", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CGCRef,GetGCFlag), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("gc", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CGCRef,GetRefCount), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("gc", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CGCRef,EnumReferences), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("gc", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CGCRef,ReleaseAllReferences), asCALL_THISCALL); assert( r >= 0 );
NotifyGarbageCollectorOfNewObject()
method on the engine when initializing the class.
CGCRef *GCRef_Factory() { // Create the object and then notify the GC of its existence CGCRef *obj = new CGCRef(); int typeId = engine->GetTypeIdByDecl("gc"); engine->NotifyGarbageCollectorOfNewObject(obj, typeId); return obj; }
You may want to consider caching the typeId, so that it doesn't have to be looked up through the relatively expensive call to GetTypeIdByDecl every time an object of this type is created.
Note, if you create objects of this type from the application side, you must also notify the garbage collector of its existence, so it's a good idea to make sure all code use the same way of creating objects of this type.
void CGCRef::AddRef() { // Clear the gc flag and increase the reference counter refCount = (refCount&0x7FFFFFFF) + 1; } void CGCRef::Release() { // Clear the gc flag, decrease ref count and delete if it reaches 0 refCount &= 0x7FFFFFFF; if( --refCount == 0 ) delete this; } // Registering the addref/release behaviours r = engine->RegisterObjectBehaviour("gc", asBEHAVE_ADDREF, "void f()", asMETHOD(CGCRef,AddRef), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("gc", asBEHAVE_RELEASE, "void f()", asMETHOD(CGCRef,Release), asCALL_THISCALL); assert( r >= 0 );