Jump to content

  • Log In with Google      Sign In   
  • Create Account

- - - - -

Returning an Interface type


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
7 replies to this topic

#1 bollµ   Members   -  Reputation: 354

Like
0Likes
Like

Posted 20 February 2013 - 02:12 AM

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

 

Edited by bollµ, 20 February 2013 - 02:59 AM.

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

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


Sponsor:

#2 bollµ   Members   -  Reputation: 354

Like
0Likes
Like

Posted 20 February 2013 - 06:33 AM

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 :)


#3 Andreas Jonsson   Moderators   -  Reputation: 3366

Like
1Likes
Like

Posted 20 February 2013 - 07:30 AM

@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


Edited by Andreas Jonsson, 20 February 2013 - 07:34 AM.

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

#4 bollµ   Members   -  Reputation: 354

Like
0Likes
Like

Posted 20 February 2013 - 10:04 PM

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?

 

 

 


Edited by bollµ, 21 February 2013 - 01:26 AM.

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

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


#5 Andreas Jonsson   Moderators   -  Reputation: 3366

Like
0Likes
Like

Posted 21 February 2013 - 08:38 AM

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

#6 bollµ   Members   -  Reputation: 354

Like
0Likes
Like

Posted 21 February 2013 - 08:51 AM

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 :)


#7 Andreas Jonsson   Moderators   -  Reputation: 3366

Like
1Likes
Like

Posted 21 February 2013 - 10:39 AM

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

#8 bollµ   Members   -  Reputation: 354

Like
0Likes
Like

Posted 22 February 2013 - 11:28 AM

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 :)





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS