🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Null Pointer Error after application attempts to modify script object handle

Started by
0 comments, last by Sir Ementaler 8 years, 1 month ago

I'm new to angelscript and am working through a few exercises to learn more about it. I've encountered a problem that is likely the result of a key misunderstanding about how AS functions.

The exercise is to share an object between the application and AS using a pointer passed as an argument:

  1. App: Instantiate object.
  2. App: Execute script
  3. Script: Instantiate object handle
  4. Script: Call application function with handle as argument
  5. App function: Set object pointer (handle) to object address. Return.
  6. Script: modify object (through handle). End.
  7. App: use object. End.

The error occurs once the script attempts to modify the object through the handle (step 6). The handle still points to null, suggesting that the address assignment did not occur correctly. What am I missing here?

My goal with this post is mostly to understand why my current solution does not work but I'm also interested to know if there are other ways to share objects without registering them as a global property.

Registering the object (Person)

[source]
//register the type
r = engine->RegisterObjectType("Person", 0, asOBJ_REF); assert(r>=0);

//register the object properties
r = engine->RegisterObjectProperty("Person", "string name", asOFFSET(Person, name)); assert(r>=0);
r = engine->RegisterObjectProperty("Person", "int age", asOFFSET(Person, age)); assert(r>=0);

//register the constructors
r = engine->RegisterObjectBehaviour("Person", asBEHAVE_FACTORY, "Person@ f()", asFUNCTION(PersonFactory), asCALL_CDECL); assert( r >= 0 );

//register the behaviors
r = engine->RegisterObjectBehaviour("Person", asBEHAVE_ADDREF, "void f()", asMETHOD(Person,AddRef), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("Person", asBEHAVE_RELEASE, "void f()", asMETHOD(Person,Release), asCALL_THISCALL); assert( r >= 0 );[/source]

Function to be called from script:

[source]

r = engine->RegisterGlobalFunction("void GetPersonInstance(Person@)", asFUNCTION(GetPersonInstance), asCALL_CDECL);

...

Person person1;

void GetPersonInstance(Person *ptr)
{
ptr = &person1;
}
[/source]

script code:

[source]

void main()
{
Person@ b;

GetPersonInstance(@b);

b.name = "Jane";
b.age = 40;
}

[/source]

Advertisement

Does your C++ compiler not give you a warning on this function?


void GetPersonInstance(Person *ptr)
{   
    ptr = &person1;
}

Because it doesn't have any effect, and ptr is a variable that's set but never read. Your problem seems to come from misunderstanding how C++ works rather than AS. You probably heard something about returning values by pointer, but that's not how you do that. In this function, ptr is a local variable of type "pointer to Person". As a local variable, it will be destroyed once it goes out of scope, i.e. when the function returns. Modifying its value is therefore not useful, and certainly doesn't affect anything outside of the function. Now, modifying *ptr could have effect outside of the function, assuming ptr were a valid pointer on entry, however that's probably not what you're trying to achieve.

There are two possible solutions. The one that seems obvious to me is to return the pointer rather than take is as argument:


Person *GetPersonInstance()
{   
    return &person1;
}

There doesn't seem to be any reason not to do that. If you want to obtain a value rather than provide it, it should seem reasonable that it should be returned by the function rather than taken. The AS function signature in this case should be changed to "Person@ GetPersonInstance()". On the other hand, if you insist on your current syntax, you can always pass the pointer by reference:


void GetPersonInstance(Person *&ptr)
{   
    ptr = &person1;
}

I wouldn't choose this solution, but it's also available. The AS function signature in this case would be "void GetPersonInstance(Person@ &out)". If I remember how AS works correctly, there's one more issue with doing either of those, and it's that since your object is garbage-collected, you should increase its reference count before returning its handle from a C++ function, by calling


person1.AddRef();

Otherwise you may experience unpleasant behavior.

This topic is closed to new replies.

Advertisement