• 13
• 16
• 27
• 9
• 9

# Lua: Tables only in scope during function call...

This topic is 3408 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi all, I have some C++ methods I'm calling from Lua. One of them looke like this:
static int MakePoint(lua_State *L)
{
Point p = {p.x = lua_tointeger(L,1), p.y =lua_tointeger(L,2)};
lua_pushlightuserdata((void*)&p);
return 0;
}

What i'm trying to do is run a simple script like this:
a = MakePoint(23,33);
b = MakePoint(10,10);

(AddPoints just simple makes a new point with a=a.x+b.x & b=a.y+b.y and stores the value in my C++ app) but a & b are always coming back into the AddPoints C++ code as nill/null. I realise a table is only good per function call, so I assigned the lightuserdata that MakePoint pushes to a variable inside lua... though this does not seem to work. Do "a" anf "b" get disguarded after their calls to MakePoint? is there anyway to make lua persist the Point lightuserdata? Thanks.

##### Share on other sites
There are a couple of problems with your code. The first is that you are pushing a pointer to local data. When the function returns, the pointer will become invalid.

The second is simpler, but you indicate the number of return values using the integer returned from the function. So, to return a single light userdata value, you would need to return 1 from the function. Remember Lua matches the number of values on the left and right of an assignment.

So a,b = 1 means a = 1 and b = nil. Likewise, if you say a = foo(), and foo() returns nothing, then a will be nil. This is what is happening at the moment, you push the pointer, but you inform Lua that you have nothing to return, so the function appears to return nil. But really, it returns nothing, and the assignment operator "fills the gaps" left when the function fails to return enough values for the variables on the left hand side.

What you can do instead is to use full user data objects. This avoids dealing with the lifetime issues with light user data. Assuming the "Point" is a POD type:
static int MakePoint(lua_State *L){    int x = lua_tointeger(L,1);    int y = lua_tointeger(L,2);    void *ptr = lua_newuserdata(L,sizeof(Point));    Point *point = static_cast<Point *>(ptr);    point->x = x;    point->y = y;    return 1;}

static int AddPoints(lua_State *L){    luaL_checktype(L, 1, LUA_TUSERDATA);    luaL_checktype(L, 2, LUA_TUSERDATA);    Point *a = static_cast<Point *>(lua_touserdata(L,1));    Point *b = static_cast<Point *>(lua_touserdata(L,2));    void *ptr = lua_newuserdata(L,sizeof(Point));    Point *point = static_cast<Point *>(ptr);    point->x = a->x + b->x;    point->y = a->y + b->y;    return 1;}

This chapter is well worth a read. In particular, the above implementation of AddPoints is unsafe as it trusts the user to always pass the correct userdata types. We could easily corrupt memory or cause a crash by sending a different userdata type. We can make this type-safe by using some of the techniques presented in the link above.

Something that isn't addressed in the above is dealing with non-POD C++ types. If we imagine a class "Foo" with a non-trivial constructor and destructor, we can use placement new and explicit destructor calling to register the type with Lua.

There are a number of "binding" libraries from C or C++ to Lua. These can (to some degree or other) automate the task of writing the lua wrapper functions. You might want to look into them. Ones I've heard of include tolua++ and luabind.