4

I'm currently facing the problem that you can't use the __gc method for tables in Lua 5.1, as they are implemented in Lua 5.2. However, I want to release allocated native resources once the lua table gets collected. Is it possible to make a workaround which gives me the functionality of __gc metamethod in Lua 5.2 for Lua 5.1?

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
Turakar
  • 180
  • 2
  • 13
  • 2
    Use a proxy object in the table and put the `__gc` metamethod on it. When the table gets collected the proxy will then get collected and your `__gc` method will be called. Though this may require extra gc cycles. – Etan Reisner Dec 11 '14 at 15:48

1 Answers1

5

In lua 5.1 the only lua values that work with __gc metamethod is userdata. Naturally any hack or workaround will have to involve userdata in someway. Normally there is no way to just create newuserdata from the lua side but there is one "hidden" undocumented function newproxy for doing just that.

newproxy takes an optional bool or userdata parameter. If you pass in true then you get a userdata with a new metatable attached. If you pass in another userdata then the new userdata will be assigned the same metatable as the one passed in.

So now you can just hack together a function that'll make __gc work on tables:

function setmt__gc(t, mt)
  local prox = newproxy(true)
  getmetatable(prox).__gc = function() mt.__gc(t) end
  t[prox] = true
  return setmetatable(t, mt)
end

And a quick test to confirm the behavior:

iscollected = false
function gctest(self)
  iscollected = true
  print("cleaning up:", self)
end

test = setmt__gc({}, {__gc = gctest})
collectgarbage()
assert(not iscollected)

test = nil
collectgarbage()
assert(iscollected)

IDEOne Demo

Note that lua 5.2+ and later no longer have newproxy since __gc is officially supported on tables.

greatwolf
  • 20,287
  • 13
  • 71
  • 105
  • There is one thing to concern while using suggested solution - if you will traverse the table by pairs() you will get one addition key. It is possibly to avoid it by using proxy object with proper metamethods in place of original table. – Alexander Altshuler Dec 12 '14 at 11:03
  • What do you mean by that? – Turakar Dec 14 '14 at 10:03