Луа слабые ссылки - PullRequest
       21

Луа слабые ссылки

2 голосов
/ 17 сентября 2011

Я работаю над проектом в Lua, где я буду создавать таблицы и хранить их в мастер-таблице, которая будет стерта позже. Я передам ссылки на эти таблицы другим родным таблицам.

master = {}
table.insert(master, {name = 'hello'})
table.insert(master, {name = 'world', pre = master[1]})

Проблема, которая возникает, заключается в том, что когда я хочу стереть ссылку из мастер-таблицы, ссылка все равно остается здесь в мастере [2]. Очевидно, мое первое решение состояло в том, чтобы таблицы имели слабые значения. (в режиме .__ на метатаблице, здесь не показывается)

Это сработало и сработало бы до тех пор, пока я бы никогда не сохранил таблицу с одиночной ссылкой в ​​этих таблицах.

table.insert(master, {name = 'goodbye', pre = master[2], some_table = {123}})

Третий элемент, some_table, в конечном итоге будет собран, поскольку таблицы имеют слабые значения, и на эту таблицу (some_table) больше нигде нет ссылок. Это нежелательное поведение. Мое последнее решение заключается в создании «слабых ссылочных объектов» для таблиц в основной таблице. Вот наивная реализация:

function WeakRef(t)
    r = {__mode = 'v', __index = t, __newindex = t}
    setmetatable(r, r)
    return r
end

Эти слабые эталонные объекты действуют аналогично boost::weak_ptr с и достигают моей цели, но я не уверен, являются ли они лучшим решением моей проблемы.

Есть ли лучший способ; более элегантное решение? Возможно, мой дизайн, для которого требуется этот мастер-стол, некорректен?

1 Ответ

2 голосов
/ 17 сентября 2011

Учитывая, что:

  1. Вы хотите, чтобы master был "одним местом", где вы определяете, существует объект или нет
  2. Ваши объекты могут иметь связи между ними

Тогда, вероятно, самая простая архитектура резервирует одного из членов каждого объекта как «посредника», отвечающего за управление ссылками на других.Вот шаги:

  1. Сделать master обычной таблицей (не слабой)
  2. На каждом физическом объекте создайте слабую таблицу с именем links (или любое другое имя, которое подходитваша логика лучше)
  3. Сделайте все links таблицами слабыми.Используйте их для хранения ссылок на другие объекты.

И это возможная реализация.Я пробовал это в Lua 5.1:

local function newWeakTable()
  return setmetatable({}, {__mode = "v"})
end

local master = {}

-- create two physical objects
local obj1 = { name = "obj1", links = newWeakTable() }
local obj2 = { name = "obj2", links = newWeakTable() }

-- link them
obj2.links.pre = obj1

-- insert them into master
table.insert(master, obj1)
table.insert(master, obj2)

-- master has 2 objects, and they are linked
assert(#master == 2)
assert(obj2.links.pre == obj1)

-- remove obj1 from master, and remove the variable reference
table.remove(master, 1)
obj1 = nil

-- run gc manually
collectgarbage("collect")

-- master has only 1 object now, and the link has dissapeared
assert(#master == 1)
assert(obj2.links.pre == nil)

print("Everything went as expected")
...