Hi i ran into a little problem related to when i want to inherit from a registered class using the mechanism explained here:
https://www.angelcode.com/angelscript/sdk/docs/manual/doc_adv_inheritappclass.html
// Angelscript side
shared abstract class FSMState
{
private FSMStateProxy@ instance;
FSMState() { @instance = FSMStateProxy(); }
void Enter(void) {}
void Exit(void) {}
void AddAction(const Variant& in action) { instance.AddAction(action); }
void RemoveAction(const StringHash &in actionID) { instance.RemoveAction(actionID); }
}
class PlayerMoveState : FSMState
{
PlayerMoveState()
{
Printf("Hi");
}
}
// function logic thats uses classes
{
PlayerMoveState moveState;
controller.AddState(moveState);
}
///////////////////////////////////////////////
C++ side .cpp
///////////////////////////////////////////////
ScriptProxyRefCountedObject::ScriptProxyRefCountedObject(asIScriptObject* object)
: GTL::RefCountedObject()
, m_objectInstance(object)
, m_bIsDead(object->GetWeakRefFlag())
{
// increment weak ref as we want to hold a reference to the object
m_bIsDead->AddRef();
// note: internal counter starts of with (1) for script objects
RefCountedObject::AddRef();
CHECK(m_objectInstance && m_bIsDead);
}
ScriptProxyRefCountedObject::~ScriptProxyRefCountedObject()
{
m_bIsDead->Release();
}
// add/release for managing object
unsigned ScriptProxyRefCountedObject::AddRef(void) const
{
// increment angelscript side counter as well to made sure it doest not get destroyed
// before the c++ side
if (!m_bIsDead->Get())
m_objectInstance->AddRef();
return GTL::RefCountedObject::AddRef();
}
unsigned ScriptProxyRefCountedObject::Release(void) const
{
// release angelscript instance as well
if (!m_bIsDead->Get())
m_objectInstance->Release();
return GTL::RefCountedObject::Release();
}
}
The problem stems when "controller.AddState()" gets called because. Since Add state executes a copy of the object. It has to create a second instance and invoke the ScriptObject::operator= for each property within the script object.
So we have CopyA: ScriptObject::RefCount = 1 Proxy::WeakRef=2 Proxy::m_objectInstance = 1 where (Proxy::m_objectInstance == ScriptObject::RefCount)
CopyB: ScriptObject::RefCount = 1 Proxy::WeakRef=2 Proxy::m_objectInstance = 1 where (Proxy::m_objectInstance == ScriptObject::RefCount)
When the script object invokes the operator= it will invoke the CopyHandle function and perform a Release on the destination handle and then an add-ref on the source handle. Then assigns the new handle. The problem is that for any proxy thats hits this operator= with both instance at a ref-count = 1. Then the release call in the CopyHandle will invoke CopyA::ScriptProxyRefCountedObject::Release, invoking m_objectInstance->Release() and thus Destroying the whole scriptObject. Destroying the script object will force the same CopyA::m_objectInstance->Release() function be called in the destructor. When the logic finishes invoking and goes back up to the operator= call stack, then we crash as 'this' pointer aka the object that was destroyed got nuked.
Hope that explains my problem. Hoping @WitchLord can help or elaborate on something im missing with regards to the example shown in the docs. This crash should happen given the example code
below which is given in the angelscript documentation and i just added an additional function.
void TestFunction(FooDerived &in CopyA)
{
}
void main()
{
// When newly created the m_value is 0
FooDerived d;
assert( d.m_value == 0 );
// invoking this function should force a copy to be created and the asIScriptObject::operator= to be called
// where internal ref-count of the object stored in the proxy are both = 1. Crash occurs
TestFunction(d);
// When calling the method the m_value is incremented with 1
d.CallMe();
assert( d.m_value == 1 );
}
please let me know if im missing something in regards on how to property handle proxy inheritance.