I have a line of code in Lua like this:
mv.getLabelChildByNameSequence("confirm_btn|button|no_icon_txt").setVisible(false);
getLabelChildByNameSequence()
returns a userdata
object (created c-side), and then setVisible()
calls a function on that object. The problem is, that works most of the time, but sometimes, the garbage collector decides to destroy the intermediate object immediately after creation, and before the second part of the statement happens.
I've found this to be more successful:
local no_icon_txt = mv.getLabelChildByNameSequence("confirm_btn|button|no_icon_txt");
no_icon_txt.setVisible(false);
I suspect that with the explicit local
variable, the ref counting works as expected, and the object doesn't get garbage collected until the local variable falls out of scope.
I would much prefer the first example to the second - it's a lot more compact and pretty looking, and more like what you would see in a language like c++
. How can I achieve this?
BTW, when the crash happens, it does seem to try to resolve the call to setVisible()
to the object's old memory address, despite having just garbage collected that data. Curious.
EDIT: I want to mention I'm using LunaFive
for the bindings (http://lua-users.org/wiki/LunaFive). The user data push fn looks like this:
static void push(lua_State * L, T* instance )
{
T **a = (T **) lua_newuserdata(L, sizeof(T *)); // Create userdata
*a = instance;
luaL_getmetatable(L, T::className);
lua_setmetatable(L, -2);
}
and the function dispatch looks like this:
static int function_dispatch(lua_State * L)
{
int i = (int) lua_tonumber(L, lua_upvalueindex(1));
T** obj = static_cast < T ** >(lua_touserdata(L, lua_upvalueindex(2)));
return ((*obj)->*(T::methods[i].func)) (L);
}
getLabelChildByNameSequence()
pushes a new instance of the Label
class (let's say), and setVisible()
is a method on that class.
get_userdata().func()
and never inget_userdata():func()
– Egor SkriptunoffuserData.setVisible(false)
doesn't actually call a function onuserData
, because the dot notation doesn't supplyuserData
as an argument to theuserData.setVisible
function. The only argument it supplies isfalse
. Colon notation,userData:setVisible(false)
, would though, because it is roughly equivalent touserData.setVisible(userData, false)
. I don't know how theuserData.setVisible
function is supposed to access theuserData
if it is not receiving it as an argument. Maybe you could show the C code foruserData.setVisible
. – cyclaministgetLabelChildByNameSequence()
, and there's nothing preventing that object collection after retrieving the function. You need the reference to userdata somewhere - either passed as first argument tosetVisible()
by using colon syntax, or by saving the reference insetVisible()
upvalues. You need the reference to userdata to modify its visibility either way. – VladsetVisible()
are NOT automatically anchored somewhere until you anchor them manually. – Egor Skriptunoff