Advertisement

std::string returned via reference

Started by June 30, 2011 10:57 AM
9 comments, last by xynapse 13 years, 7 months ago
Hi guys,

i've run into a small problem.

Here's what i do exactly:





//Definition of a single entity on the map

struct mapEntity
{
std::string class_name;
std::string model_name;
std::string entity_name;
CVector3 origin;
CVector3 color;
CVector3 angle;

};



...

...

...

//Register this structure in the angel script

eScripting->RegisterObjectType(" bspEntity",sizeof( bspEntity),asOBJ_VALUE | asOBJ_POD|asOBJ_APP_CLASS );
eScripting->RegisterObjectProperty(" bspEntity", "string class_name", offsetof( bspEntity, class_name));
eScripting->RegisterObjectProperty(" bspEntity", "string model_name", offsetof( bspEntity, model_name));
eScripting->RegisterObjectProperty(" bspEntity", "string entity_name", offsetof( bspEntity, entity_name));
eScripting->RegisterObjectProperty("bspEntity", "CVector3 origin", offsetof(bspEntity, origin));
eScripting->RegisterObjectProperty("bspEntity", "CVector3 color", offsetof(bspEntity, color));
eScripting->RegisterObjectProperty("bspEntity", "CVector3 angle", offsetof(bspEntity, angle));

//Register a method within angelscript

eScripting->RegisterObjectMethod("XBSP", "bool getEntityName(const string &in, bspEntity&out)", asMETHODPR(XBSP,XS_getEntityName, (const std::string &in, bspEntity&out), bool), asCALL_THISCALL);



//Get entity wrapper that returns found entity to the angelscript

bool XBSP::XS_getEntityName(const std::string &name, bspEntity &ret)
{

bspEntity *b = getEntityName(name);
if( b )
{

ret = *b; //FAILS HERE!
return true;


}
// entity doesn't exist
return false;
}





Right, when i call



X:: bspEntityent;
Game->Level()->XS_getEntityName("CameraPosition0",ent);



from the engine itself, all works fine - std::string is 'copied' into ent.

But when i call if from the script:





bspEntityCameraPosition;







//When true - application crashes obviously because of a angelscrtips string and std::string incompatibility

if(Level.getEntityName("CameraPosition0",CameraPosition)==true)
{

Log("Entity found");

}


else

{


Log("No entity");

}





I get an application crash, pointing to





> x.exe!memcpy(unsigned char * dst=0xcdcdcdcd, unsigned char * src=0x04ca9f14, unsigned long count=13) Line 232 Asm
x.exe!std::char_traits<char>::copy(char * _First1=0xcdcdcdcd, const char * _First2=0x04ca9f14, unsigned int _Count=13) Line 497 + 0x11 bytes C++
x.exe!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign(const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & _Right="Camera_static", unsigned int _Roff=0, unsigned int _Count=4294967295) Line 904 + 0x1e bytes C++
x.exe!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign(const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & _Right="Camera_static") Line 889 C++
x.exe!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::operator=(const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & _Right="Camera_static") Line 765 C++
x.exe!X::bspEntity::operator=(const X::bspEntity & __that={...}) + 0x2f bytes C++
x.exe!X::XBSP::XS_getEntityName(const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & name="CameraPosition0", X::bspEntity & ret={...}) Line 2337 C++




Which in this case is a problem with std::string that is to be returned into the angelscript.
There is no problem when i remove std::string from the structure definition, but i need those strings in the structure for later in-script usage.

The std::strings are marked as <bad-ptr's> in debugger,



+ ret {class_name=<Bad Ptr> model_name=<Bad Ptr> entity_name=<Bad Ptr> ...} X::bspEntity &


+ b 0x04ca9f10 {class_name="Camera_static" model_name="" entity_name="CameraPosition0" ...} X::bspEntity *






Additionaly, when i change:



ret = *b;



to



ret.class_name=b->class_name;






The application crashes too.



+ ret {class_name=<Bad Ptr> model_name=<Bad Ptr> entity_name=<Bad Ptr> ...} X::bspEntity &
+ b 0x04ca9f10 {class_name="Camera_static" model_name="" entity_name="CameraPosition0" ...} X::bspEntity *







But when i do:






//ret = *b;

//TEST: CVector3 from found entity
ret.angle=b->angle;





The application works fine, so it is a std::string issue and i hope we can overcome this...







Is there any chance i can return std::string into the angelscript?
perfection.is.the.key
How did you register strings with AngelScript?
Advertisement
It goes with






RegisterScriptString(eScripting);






CScriptString class that was taken from angelscript

scriptstring.h

perfection.is.the.key
Since you're using std::strings as value types, you probably want to use the scriptstdstring add-on rather than scriptstring.
Damn!




SiCrane, you're right!




Let me quickly have a look at this...







perfection.is.the.key
Registered STD::STRING now with

RegisterStdString(eScripting);




and the same error occurs...
perfection.is.the.key
Advertisement
Try changing


eScripting->RegisterObjectType(" bspEntity",sizeof( bspEntity),asOBJ_VALUE | asOBJ_POD|asOBJ_APP_CLASS );


to


eScripting->RegisterObjectType(" bspEntity",sizeof( bspEntity),asOBJ_VALUE | asOBJ_APP_CLASS );


I don't believe a class containing strings is valid for asOBJ_POD.
Immortius,

Now AS is dropping errors:






eScripting->RegisterObjectType("tEntity",sizeof(tEntity),asOBJ_VALUE | asOBJ_APP_CLASS );



Engine log:

[23026546] [] Error, Type tEntityis missing behaviours (Line 0/0)
[23026546] [] A non-pod value type must have the default constructor and destructor behaviours (Line 0/0)
[23026546] [] Error, Invalid configuration (Line 0/0)




Ps. i changed the name from bspEntity to tEntity meantime to fit to the engine requirements.




perfection.is.the.key
Ok, tried almost everything i am aware of,




the application crashes only when a std::string to AS is returned, all other types (int,floats,... , CVector3 and other defined within my engine) are returned OK.




Again to sum it all up,



// Entity object in engine

struct tEntity
{
std::string class_name;
std::string model_name;
std::string entity_name;

CVector3 origin;
CVector3 color;
CVector3 angle;
};





//tEntity object in AS

eScripting->RegisterObjectType("tEntity",sizeof(tEntity), asOBJ_VALUE | asOBJ_POD|asOBJ_APP_CLASS );
eScripting->RegisterObjectProperty("tEntity", "string class_name", offsetof(tEntity, class_name));
eScripting->RegisterObjectProperty("tEntity", "string model_name", offsetof(tEntity, model_name));
eScripting->RegisterObjectProperty("tEntity", "string entity_name", offsetof(tEntity, entity_name));
eScripting->RegisterObjectProperty("tEntity", "CVector3 origin", offsetof(tEntity, origin));
eScripting->RegisterObjectProperty("tEntity", "CVector3 color", offsetof(tEntity, color));
eScripting->RegisterObjectProperty("tEntity", "CVector3 angle", offsetof(tEntity, angle));




//GetEntity safe wrapper for AS

bool XBSP::XS_getEntityName(const std::string &name, tEntity &ret)
{

tEntity *b = getEntityName(name);
if( b )
{

ret = *b;
return true;

}
// entity doesn't exist
return false;
}





//Wrapper registration within AS

eScripting->RegisterObjectMethod("XBSP", "bool getEntityName(const string &in, tEntity &out)", asMETHODPR(XBSP,XS_getEntityName, (const std::string &in,tEntity &out), bool), asCALL_THISCALL);







When getEntityName is called within AS a wrapper XS_getEntityName is injected within engine.

When entity is found,



tEntity *b = getEntityName(name);

if( b )

{

ret = *b;

}






Causes application crash when 'copying' std::string back to AS



+ ret {class_name=<Bad Ptr> model_name=<Bad Ptr> entity_name=<Bad Ptr> ...} X::bspEntity &


+ b 0x04ca9f10 {class_name="Camera_static" model_name="" entity_name="CameraPosition0" ...} X::bspEntity *






When i do it without strings:



tEntity *b = getEntityName(name);

if( b )

{
////ret = *b;


ret.angle=b->angle;
ret.color=b->color;
ret.origin=b->origin;


}






Voilla, all works great!







I register the strings with : RegisterStdString(eScripting);




I am starting to believe this looks like a bug.. (hopefully not, and i'm doing something wrong..)
perfection.is.the.key
Manual: Registering a value type

As the tEntity struct contains std::strings, you must not register it with asOBJ_POD. You must also register the asBEHAVE_CONSTRUCT and asBEHAVE_DESTRUCT behaviours for the type to properly initialize the members and release the memory of the strings when the object is destroyed.


#include <new> // placement new
void tEntity_Construct(tEntity *o)
{
// Call the constructor to initialize the already allocated memory
new(o) tEntity;
}

void tEntity_Destruct(tEntity *o)
{
// Call the destructor to release the memory that the members hold
o->~tEntity();
}


//tEntity object in AS

eScripting->RegisterObjectType("tEntity",sizeof(tEntity), asOBJ_VALUE | asOBJ_APP_CLASS );
eScripting->RegisterObjectBehaviour("tEntity", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(tEntity_Construct), asCALL_CDECL_OBJLAST);
eScripting->RegisterObjectBehaviour("tEntity", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(tEntity_Destruct), asCALL_CDECL_OBJLAST);


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

This topic is closed to new replies.

Advertisement