Jump to content
  • Advertisement
Sign in to follow this  
calzone

Null Pointer Error after application attempts to modify script object handle

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

If you intended to correct an error in the post then please contact us.

Recommended Posts

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]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!