🎉 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!

Returning a class

Started by
6 comments, last by WitchLord 18 years, 10 months ago
Hello! I wanted to write code which will handle such operations in the script: CSomeClass class; class = Master.FindSub(...); I don't know if I did that properly, because I'm receiving some not very pleasant errors. Here is what I did: Master class:

class CMaster
{
public:
	CMaster(){};
	~CMaster(){};

	CSomeClass FindSub( int index )
	{
		CSomeClass cl;
		return cl;
	}
};
Here I register CSomeClass:

	r = ScriptEngine->RegisterObjectType("CSomeClass", sizeof(CSomeClass), asOBJ_CLASS_CDA);assert(r>=0);
	r=ScriptEngine->RegisterObjectBehaviour("CSomeClass", asBEHAVE_CONSTRUCT, "void f()", asFUNCTIONPR(Constructor, (CSomeClass*), void), asCALL_CDECL_OBJLAST); assert(r >= 0);
	r=ScriptEngine->RegisterObjectBehaviour("CSomeClass", asBEHAVE_DESTRUCT, "void f()", asFUNCTIONPR(Destructor, (CSomeClass&), void), asCALL_CDECL_OBJLAST); assert(r >= 0);
	r=ScriptEngine->RegisterObjectBehaviour("CSomeClass", asBEHAVE_ADDREF, "void f()", asMETHOD(CSomeClass, AddRef), asCALL_THISCALL); assert(r >= 0);
	r=ScriptEngine->RegisterObjectBehaviour("CSomeClass", asBEHAVE_RELEASE, "void f()", asMETHOD(CSomeClass, Release), asCALL_THISCALL); assert(r >= 0);
Here is it's declaration:

class CSomeClass
{
public:	
	CSomeClass(): refcount(1) {};
	~CSomeClass()
	{
	}
	void AddRef(){refcount++;}
	void Release(){ if(--refcount == 0) delete this;}
private:
	int refcount;
};
Here I register the CMaster class:

	r = ScriptEngine->RegisterObjectType("CMaster",sizeof(CMaster), asCALL_CDECL);assert(r >= 0);
	r = ScriptEngine->RegisterGlobalProperty("CMaster Master", (void*)&Master); assert(r>=0);
	r = ScriptEngine->RegisterObjectMethod("CMaster", "CSomeClass FindSub(int index)", asMETHOD(CMaster,FindSub), asCALL_THISCALL);assert(r >= 0);
Then when I perform: CSomeClass class; class = Master.FindSub(...); I get some heap allocation errors. P.S. I hope I remembered to put everything that is of any use here. Regards, Black Dot
Falling Man GamesFeel free to visit us!
Advertisement
You cannot use reference counting with objects allocated on the stack, nor can you pass reference counted objects by value or return them by value.

Change your FindSub() to:

CSomeClass *FindSub(int index){  return new CSomeClass();}


Also register the method with:

r = ScriptEngine->RegisterObjectMethod("CMaster", "CSomeClass@ FindSub(int index)", asMETHOD(CMaster,FindSub), asCALL_THISCALL); assert(r >= 0);


This should be the only thing you need to change to get things working.

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

Thank you, WitchLord.

Everything works fine now.
Falling Man GamesFeel free to visit us!
Quote: class = Master.FindSub(...);


It might just seem to be working correctly. You didn't bind an operator=, but you are using it.
Well spotted!

The assignment behaviour is indeed a must when using reference counting. Without it AngelScript will just do a bit-by-bit copy of the objects, overwriting any reference counters, which will lead to problems later on.

I'll change the way objects are registered to have the engine detect when behaviours aren't registered. It will still be possible to use the default behaviour, but it has to be a conscious choice.

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

I was thinking that that might be the case, but Black Dot told me that everything was working fine afterwards.

It seemed strange to me that you can do this in C++

 using namespace std;    class MyClass  {  public:       MyClass() : refcount(1){};       ~MyClass(){};         void AddRef(){refcount++;}       void Release()       {            if(--refcount == 0)                 delete this;       }         int GetRefcount(){return refcount;}         void PrintMessage()       {            cout << "this is a message" << endl;       }  private:       int refcount;  };    MyClass GetMyClass()  {       MyClass f;       return f;  }      int _tmain(int argc, _TCHAR* argv[])  {       MyClass f = GetMyClass();       cout << f.GetRefcount() << endl;       f.PrintMessage();       system("pause");       return 0;  } 


But if you tried the same thing in AS it would fail.
You can do that in anglescript. You did
myclass instance = new_instance;

He did
myclass instance = default_instance;instance = new_instance;

The first compiles in C++ because it doesn't call operator=. It still isn't any good if you don't have a proper copy constructor.
In the C++ function the object is allocated on the stack, but in AngelScript objects are allocated on the heap. Thus, when AngelScript receives the object from the C++ function it will call the Release() method to free the object, which in turn will call delete on the object pointer. Delete on objects allocated on the stack may result in unexpected behaviour, maybe even crash the application.

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

This topic is closed to new replies.

Advertisement