Временное решение Lua 5.1 для метаметода __gc для таблиц

В настоящее время я сталкиваюсь с проблемой, что вы не можете использовать __gc метод для таблиц в Lua 5.1, так как они реализованы в Lua 5.2. Тем не менее, я хочу освободить выделенные собственные ресурсы, как только таблица lua будет собрана. Можно ли сделать обходной путь, который дает мне функциональность __gc метаметод в Lua 5.2 для Lua 5.1?

1 ответ

Решение

В lua 5.1 единственные значения lua, которые работают с __gc метаметод userdata, Естественно, любой взлом или обходной путь должен будет включать userdata каким-то образом. Обычно нет способа просто создать newuserdata со стороны lua, но есть одна "скрытая" недокументированная функция newproxy для этого просто.

newproxy принимает необязательный параметр bool или userdata. Если вы проходите в true тогда вы получите пользовательские данные с новым прикрепленным метатабилем. Если вы переходите в другой userdata тогда новым userdata будет назначена та же метатабельная, что и переданной.

Так что теперь вы можете просто взломать функцию, которая сделает __gc работа на столах:

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

И быстрый тест, чтобы подтвердить поведение:

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

Обратите внимание, что Lua 5.2+ и более поздних версий больше не имеют newproxy поскольку __gc официально поддерживается на столах.

Другие вопросы по тегам