Lua弱参考

时间:2011-09-17 00:55:07

标签: garbage-collection lua weak-references

我正在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的行为类似,可以实现我的目标,但我不确定它们是否是解决我问题的最佳方法。

有没有更好的方法;更优雅的解决方案? 我的设计,需要这个主表,可能有缺陷吗?

1 个答案:

答案 0 :(得分:2)

鉴于:

  1. 您希望master成为您定义对象是否存在的“一个地方”
  2. 您的对象之间可以有链接
  3. 然后,最简单的架构可能是将每个对象的一个​​成员保留为负责管理对他人的引用的“中间人”。以下是步骤:

    1. 使master成为常规表(不弱)
    2. 在每个物理对象上,创建一个名为links的弱表(或更适合您逻辑的名称)
    3. 使所有links表格变弱。使用它们存储对其他对象的引用。
    4. 这是一种可能的实施方式。我在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")