我正在Lua的一个项目中,我将创建表并将它们存储在主表中,以便稍后擦除。我会将对这些表的引用传递给其他兄弟表。
master = {}
table.insert(master, {name = 'hello'})
table.insert(master, {name = 'world', pre = master[1]})
出现的问题是,当我希望从主表中删除引用时,引用仍然保留在master [2]中。显然,我的第一个解决方案是使表格具有较弱的值。 (通过metatable上的.__模式,此处未显示)
只要我永远不会在这些表中存储单引号表,这样就可以工作了。
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
的行为类似,可以实现我的目标,但我不确定它们是否是解决我问题的最佳方法。
有没有更好的方法;更优雅的解决方案? 我的设计,需要这个主表,可能有缺陷吗?
答案 0 :(得分:2)
鉴于:
然后,最简单的架构可能是将每个对象的一个成员保留为负责管理对他人的引用的“中间人”。以下是步骤:
master
成为常规表(不弱)links
的弱表(或更适合您逻辑的名称)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")