This topic is 1347 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I want to be able to instantiate different classes based on a string, to do that I use this C++ function:
void InstantiateClass(asIScriptGeneric *gen)
{
auto name = (std::string*)gen->GetArgObject(0);

auto mod = gen->GetEngine()->GetModule("Scripts");
auto type = mod->GetObjectTypeByName(name->c_str());

if (!type)
{
printf("%s '%s'\n", "Couldn't find class", name->c_str());

auto ret = CScriptHandle();
return;
}

auto tName = std::string(type->GetName());
auto factory = type->GetFactoryByDecl((tName + "@ " + tName + "(SValue& params)").c_str());

if (!factory)
{
printf("%s '%s' %s\n", "Couldn't find class", name->c_str(), "factory function");

auto ret = CScriptHandle();
return;
}

auto ctx = gen->GetEngine()->CreateContext();

ScriptEngine::PrepareContext(ctx, factory);
int r = ctx->SetArgObject(0, params); assert(r >= 0);
ScriptEngine::VerifyScriptExecution(ctx, ctx->Execute());

ScriptEngine::UnprepareContext(ctx);

auto ret = CScriptHandle(bObj, type);
ctx->Release();

}

This has worked well for me for a while now, but now I'm getting a crash when trying to use it on some really simple classes. It seems like when the CScriptHandle does engine->AddRefScriptObject it will crash if the class doesn't contain an object handle.

So doing it on this class works:
class Explode : IAction
{
IAction@ dummy;

Explode(SValue& params)
{
}

bool DoAction(Actor@ owner, vec2 pos, vec2 dir)
{
return true;
}

void Update(int dt, int cooldown)
{
}
}

But if I remove IAction@ dummy, I get a crash in "void asCScriptEngine::CallObjectMethod(void *obj, asSSystemFunctionInterface *i, asCScriptFunction *s) const".

##### Share on other sites

I see a couple of errors in your code. It is probably by luck that it hasn't given you trouble before.

void InstantiateClass(asIScriptGeneric *gen)
{
auto name = (std::string*)gen->GetArgObject(0);

auto mod = gen->GetEngine()->GetModule("Scripts");
auto type = mod->GetObjectTypeByName(name->c_str());

if (!type)
{
printf("%s '%s'\n", "Couldn't find class", name->c_str());

//auto ret = CScriptHandle();
//*(CScriptHandle*)gen->GetAddressOfReturnLocation() = ret;  // <-- The memory is not yet initialized, so you cannot do an assignment on it
new( gen->GetAddressOfReturnLocation() ) CScriptHandle();   // <-- You must initialize the memory using the placement new() operator
return;
}

auto tName = std::string(type->GetName());
auto factory = type->GetFactoryByDecl((tName + "@ " + tName + "(SValue& params)").c_str());

if (!factory)
{
printf("%s '%s' %s\n", "Couldn't find class", name->c_str(), "factory function");

//auto ret = CScriptHandle();
//*(CScriptHandle*)gen->GetAddressOfReturnLocation() = ret;  // <-- The memory is not yet initialized, so you cannot do an assignment on it
new( gen->GetAddressOfReturnLocation() ) CScriptHandle();   // <-- You must initialize the memory using the placement new() operator
return;
}

auto ctx = gen->GetEngine()->CreateContext();

ScriptEngine::PrepareContext(ctx, factory);
int r = ctx->SetArgObject(0, params); assert(r >= 0);
ScriptEngine::VerifyScriptExecution(ctx, ctx->Execute());

// ScriptEngine::UnprepareContext(ctx); // <-- This releases the reference to the object held by the context, thus destroying it before you give it to the CScriptHandle
// auto ret = CScriptHandle(bObj, type); // <-- The script handle will increment the ref count to take ownership of the object
// ctx->Release(); // <-- Destroying the context automatically unprepares it, so there is no need to explicitly call Unprepare() unless you're using context pooling
// *(CScriptHandle*)gen->GetAddressOfReturnLocation() = ret; // <-- The memory is not yet initialized so this assignment is incorrect

new( gen->GetAddressOfReturnLocation() ) CScriptHandle(bObj, type); // <-- Use placement new to initalize the memory
ctx->Release(); // <-- Release the context after initializing the script handle to avoid it being destroyed too early
}


The fact that it doesn't crash when the script class has a handle as member is because that member causes the class to be garbage collected as it can potentially form circular references. This in turn makes the garbage collector hold on to a reference to the object in order to properly control the life time, which is how the object was kept alive long enough for the CScriptHandle to call AddRefScriptObject on it. When the class doesn't have the handle, the script object was destroyed immediately upon ctx->Unprepare() thus turning the bObj pointer invalid even before you could pass it to the CScriptHandle instance.

Regards,

Andreas

##### Share on other sites

Aha, thank you. That makes a lot of sense.

1. 1
2. 2
3. 3
4. 4
5. 5
Rutin
18

• 11
• 12
• 9
• 12
• 37
• ### Forum Statistics

• Total Topics
631420
• Total Posts
2999990
×