I have a problem where if I store a handle to an object in a script class object, it gets deleted when it shouldn't.
So, the script looks like this:
class MainClass{ CEntity@ entity; MainClass() {}; void Init(CEntity& ent) { @entity = ent; }}
CEntity comes from C++, and is declared with behaviors of ADDREF and RELEASE, but no FACTORY or assignment operator.
It also has a defined implicit cast to a CBaseEntity, but CBaseEntity doesn't have any behaviors defined except ADDREF and RELEASE.
What I do is I create an object of type MainClass, and then store it inside of my CEntity (actually it's wrapped in another class, but in a pretty basic way). When I receive the object from the factory, I call AddRef on it.
Then I call its init method, sending 'this' as the parameter. The script works fine - any code I put in it that manipulates the entity works.
However, when deleting the entity, I call Release() on the script object, and then somehow it calls the destructor on my CEntity, so that destructor gets called twice.
It may sound like a wrong reference count, but that's not it. First of all, if I put a breakpoint in the destructor, the reference count of that object (CEntity) is 2 at that point. Second, there is a special flag in that object which prevents it from getting deleted even if its reference count reaches zero.
Basically, we didn't want to change our code to use reference counting, because that would be way too much work. So I've come up with a little trick: there is a bool flag in each of those reference counted objects, telling me whether it was created in the native code or in the script engine. If it was created in the native code, its "Release" method will simply not delete it, and the native code will be held responsible for deleting it eventually.
My stack trace at the point of the second call of the destructor contains this:
MapViewer.exe!CEntity::`scalar deleting destructor'() + 0x2e bytes C++...Core.dll!asCScriptEngine::CallObjectMethod() + 0x15 bytes C++Core.dll!asCScriptObject::~asCScriptObject() + 0xae bytes C++Core.dll!asCScriptObject::`vector deleting destructor'() + 0x8 bytes C++Core.dll!asCScriptObject::Release() + 0x33 bytes C++Core.dll!asCGarbageCollector::DestroyGarbage() + 0xa5 bytes C++Core.dll!asCGarbageCollector::GarbageCollect() + 0x6c bytes C++Core.dll!asCScriptEngine::GarbageCollect() + 0xf bytes C++
The garbage collector is called by me because I wanted it to immediately delete the just released script object because the Entity is about to become invalid and it holds a reference to it.
Am I doing something obviously wrong?
I don't think I understand how those object handles actually work, when things get copied, etc.
For reference, I've also tried:
in the Init method:
@entity = @ent;
entity = ent;
entity = @ent;
I've also tried Init(CEntity@ ent), with all of the above assignment combinations too. Some don't compile, and those that do result in the same crash.
Any ideas?
Sorry for the long post :(