Using C++-Allocated Objects in Lua

Started by
1 comment, last by SeiryuEnder 11 years, 10 months ago
Right now I'm using Luna to expose my C++ classes to Lua. The problem I'm having is that I want to allocated and manage my objects in C++, only using Lua to potentially create or manipulate them.

I'm not particularly familiar with Lua. My (rather naive) first attempt was to set up a class as per some Luna tutorials, create that class using a factory, pass that class to Lua using lua_pushlightuserdata, and create an object reference in lua to the pointer in the stack.

As it turns out, Lua doesn't know how to interpret that pointer as it defines 'objects' by metatables which a raw memory address won't have. After giving it some thought, I'm currently considering creating an interface class which contains all of my Lua functions. The constructor will accept a parameter to its target class. Because it is only an interface and doesn't contain any actual data, it doesn't cost much to instantiate it whenever a script is run and let the GC clean it up.

However, not only does this seem inefficient but I completely lose type-safety. The script could theoretically pass anything into the lua interface which can crash the program (or worse). Does anyone more experienced with C++-Lua binding know how I can achieve my original goal of handing a C++ object to lua, or have any more elegant solutions? I'll add some pseudo-code below to make my problem a bit more clear.

Current Attempt:

std::vector<GameObject*> objList;

class GameObject
{
public:
void DoThing() {}
int Do( lua_State* _state ) { DoThing(); }

... insert Luna binding code
}

int CreateObject( lua_State* _state )
{
GameObject* obj = new GameObject();
objList.push_back( obj );
lua_pushlightuserdata( _state, (void*)obj );
return 1;
}


int main()
{
lua_State* state = luaL_newstate();
lua_register( state, "CreateObject", CreateObject );
luaL_loadfile( m_State, "DoSomething.lua" );
lua_pcall( state, 0, LUA_MULTRET, 0 );
lua_close( state );

return 0;
}

DoSomething.lua:
local obj = CreateObject( "LuaScript" )
obj.Do()


...This won't work because Lua doesn't know how to interpret that (void*), I incorrectly thought that it would maintain some sort of VFT-esque behavior.

The method I talked about as a potential solution would be something akin to:

class GameObject
{
public:
void DoThing() {}
};

class LIGameObject
{
public:
LIGameObject( GameObject* _target ) : m_Target(_target) {}
int Do( lua_State* _state ) { m_Target->DoThing(); }
... insert Luna binding code
private:
GameObject* m_Target;
};

int CreateObject( lua_State* _state )...
int main()...

DoSomething.lua:
obj = LIGameObject( CreateObject( "LuaScript" ) )
obj.Do()
Advertisement
I personally use tolua++. In C++, I will implement a factory class, something like this:


class Object
{
public:
// Don't bind constructor/destructor since we want objects to be managed by a factory

void foo();
static void bar();
};

class ObjectFactory
{
public:
ObjectFactory();
~ObjectFactory();

Object *createObject();
void destroyObject(Object *o);
};


Per the usage of tolua++, I'll process this header to generate the binding code. In Lua code, then, it is as simple to use as this:


factory=ObjectFactory();
object=factory:createObject();

object:foo()
object.bar()

factory:destroyObject(object)
object=nil

I personally use tolua++. In C++, I will implement a factory class, something like this:


I started out trying ToLua++ and Luabind until I found out they both use the Boost libs. Because of the bulkiness I've tried to stay away from Boost but unfortunately I may have to bite the bullet on that one... I much prefer Boost+Type Safety to no Boost+Bad Design. Your implementation looks exactly like what I wanted to do in the first place, I guess I'll back up/revert my Luna code and start working on ToLua++

This topic is closed to new replies.

Advertisement