Returning an Interface type

Started by
6 comments, last by SiddharthBhat 11 years, 1 month ago

Hi all!

I've been writing a class called "actorList", which is basically a list of all actors. I'm not using the array type because I want to extend this type to support some additional features like filtering, ordering, etc.

"Actor" is an interface. there are different types of actors in my game, such as componentActor, Light and Sound. ALL of the derived classes of Actor have turned off garbage collection (I distrust the garbage collector >_>. The script side only has restricted entry points and is not allowed to instantiate these classes. Hence, I decided to turn garbage collection off.)


class actorList{
public:
    int getSize(){
        return this->actors.size();
    };
    Actor *get(int index){
        return this->actors[index];
    };


    void  Add(Actor *a){
        this->actors.push_back(a);
    }


    void Clear(){
        this->actors.clear();
    }


    actorList(std::vector<Actor *>actors){
        this->actors = actors;
    }


    actorList(const actorList &other){
        this->actors = other.actors;
    }


    actorList(){};
    ~actorList(){};


private:
    std::vector<Actor *>actors;
};
 

I've been trying to bind " Actor *get(int index)" and I'm not able to do it :/

--------------------------------------------------------------------------------------------------------------------------------------------------

I've been binding the function this way:


//function is Actor *get(int index)
actorListDef.addMethod(AS_ObjMethodDef("Actor@ Get(int index)", 
        AS_FunctionDef(asMETHODPR(actorList, get, (int index), Actor*), asCALL_THISCALL )));
 

If I access it from the script side like so:


Actor @actor;

//this statement makes sense right? *p = *q;
@actor = @allActors.Get(i);
 
 

or like so:


Actor @actor;

//*p = q I don't know what this means 
@actor = allActors.Get(i);
 

It goes and crashes at as_engine.cpp at line number 3333. These are the surrounding lines:


void asCScriptEngine::CallObjectMethod(void *obj, int func)
{
    asCScriptFunction *s = scriptFunctions[func]; <-- this is where it crashes
    asASSERT( s != 0 );
    CallObjectMethod(obj, s->sysFuncIntf, s);
}
 

Here, the "this" appears to have been freed and has been set to Visual Studio's "memory freed" debug pattern - 0xfeeefeee


- this    0xfeeefeee {isPrepared=??? memoryMgr={cs={cs={DebugInfo=??? LockCount=??? RecursionCount=??? ...} } ...} ...}    asCScriptEngine *
 

//------------------------------------------------------------------------------------------------------------------------------------------

I also tried binding it this way:


void get(int index, Actor **a){
        *a = this->actors[index];
    }
 

Here's how I bound it to the script side:


actorListDef.addMethod(AS_ObjMethodDef("void Get(int index, Actor &out)", 
        AS_FunctionDef(asMETHODPR(actorList, get, (int index, Actor **a), void), asCALL_THISCALL )));
 

because the documentation said this:



&out : A reference to an unitialized value is passed to the function. When the function returns the value is copied to the true reference. The argument expression is evaluated only after the function call. This is the best way to have functions return multiple values.

But on doing this, it says "No default constructor for object of type 'Actor'. " as well as "There is no copy operator for the type 'Actor' available." , and then the usual unable to Prepare, unable to Exexute.

Help, Anyone? sad.png I have no clue as to what I'm doing wrong / what I'm supposed to do.

Thanks

~Bollu

a WIP 2d game engine: https://code.google.com/p/modulusengine/

English is not my first language, so do feel free to correct me :)

Advertisement

Bump?

if no one knows what to do, could I at least have some pointers as to what I maybe doing wrong and / or propose a change to the architecture? Thanks.

a WIP 2d game engine: https://code.google.com/p/modulusengine/

English is not my first language, so do feel free to correct me :)

@a = @b; means a handle assignment, i.e. handle a will point to the same object as handle b

@a = b; same thing, the compiler knows you want to do a handle assignment because of the left-hand @ and thus implicitly takes the handle of the right-hand expression

a = b; means a value assignment, i.e. the content of b will be copied to the content of a

In your first attempt, i.e. when get returned an Actor*. You forgot to increase the reference counter before returning the pointer. AngelScript will call Release() on the pointer it receives, so you must call AddRef() or else the object will be freed too early. Alternatively you can tell AngelScript to automatically increase the reference count by registering the method like this:


//function is Actor *get(int index)
actorListDef.addMethod(AS_ObjMethodDef("Actor@+ Get(int index)", 
        AS_FunctionDef(asMETHODPR(actorList, get, (int index), Actor*), asCALL_THISCALL )));

Observe the + sign after the @ symbol. This is called auto handles in the manual.

In your second attempt that returns the Actor as an output parameter, you registered the method incorrectly. It should have been registered as:


actorListDef.addMethod(AS_ObjMethodDef("void Get(int index, Actor @ &out)", 
        AS_FunctionDef(asMETHODPR(actorList, get, (int index, Actor **a), void), asCALL_THISCALL )));

The Actor @&out in AngelScript matches Actor ** in C++. Observe that here too you need to increase the reference count, or use auto handles to have AngelScript do it.

You had registered it as 'Actor &out', which matches 'Actor &' in C++, i.e. a reference to an existing instance is passed to the function to be updated with the return value. This is why you got the error 'No default constructor' when AngelScript tried to create the instance you told it to pass to the function.

Here's a few articles from the manual that may help clarify these subjects:

Regards,

Andreas

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Ah! that makes perfect sense biggrin.png. Thank you! I used the second method and It's perfectly fine now.

But I have a question: I've disabled garbage collection on these objects (Actor is an interface, so I'm not sure how to disable the GC on that) by adding the flag asOBJ_NOCOUNT while binding the interface. so shouldn't the 1st method work independent of whether I call AddRef or not? I mean, isn't the GC not supposed to clear objects that have disabled reference counting?

Thanks

~Bollu

EDIT: It's not fine, it's not crashing, but it's still returning a null pointer. I used the Angelscript debugger. The memory location of Actor @actor is still NULL (0x00...). So it's not getting copied properly.

The C++ side function:


void get(int index, Actor **a){
        *a = this->actors[index];
    }

 

Binding:


actorListDef.addMethod(AS_ObjMethodDef("void Get(int index, Actor @ &out)", 
        AS_FunctionDef(asMETHODPR(actorList, get, (int index, Actor **a), void), asCALL_THISCALL )));
 

script-side:


Actor @a;
actorList allActors = getAllActors();

allActors.Get(0, @a);
 

And yes, a valid pointer exists inside the actorList class. I put a breakpoint to check. everything is fine and all the pointers are present. The pointer to pointer even gets equated to the right memory address. but after returning from the Get function call, in the next statement, (I know this because I was stepping using angelscript's debugger), it's back to NULL.

I have no idea >.<; help, please?

a WIP 2d game engine: https://code.google.com/p/modulusengine/

English is not my first language, so do feel free to correct me :)

I'm sorry. I missunderstood what you meant by disabling garbage collection. When you said that I though you simply didn't register the garbage collector behaviours or even turned off the automatic execution of the garbage collector, not that you registered the object types with asOBJ_NOCOUNT to skip the reference counting.

To me garbage collecting and reference counting are two different things. :)

Anyway, if you register the types with asOBJ_NOCOUNT then AngelScript won't call the AddRef or Release behaviours. It won't allow you to use autohandles either for these types.

Still, you say you disabled garbage collector on all types, except Actor. What do you mean? How exactly have you registered the Actor type? Is it not registered with asOBJ_NOCOUNT as well?

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

My bad :) you're right, I've disabled reference counting.

"Actor" is an interface, it's not an object per se. I was of the opinion that one cannot register behaviours to interfaces.

using this function:


asIScriptEngine::RegisterInterface(const char * name)
 

I didn't see a parameter to pass the flags like you can to RegisterObjectType. So, I didn't do anything. just used registerInterface with Actor, and a few trivial functions (getName, getPosition) and the like.

All of the concrete derived classes of Actor (which are all reference types) have been registered with the asOBJ_NOCOUNT flag.

thanks

~Bollu

a WIP 2d game engine: https://code.google.com/p/modulusengine/

English is not my first language, so do feel free to correct me :)

Ah. There is the error. smile.png

RegisterInterface() is meant to allow you to register script interface declaration that the application needs to know of. This is not meant to be used for C++ interfaces.

When you return the Actor handle, AngelScript believes you're returning a asCScriptObject *, i.e. a script class, not a C++ class. Exactly what will happen in this case is unknown, but it is certain that you'll end up with unexpected results as you noticed. :)

You need to register your C++ Actor interface just like an ordinary C++ type, i.e. with RegisterObjectType("Actor", 0, asOBJ_REF | asOBJ_NOCOUNT);

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Thanks a bunch :) It's now returning a proper pointer!

a WIP 2d game engine: https://code.google.com/p/modulusengine/

English is not my first language, so do feel free to correct me :)

This topic is closed to new replies.

Advertisement