开发者

Lua weak references

开发者 https://www.devze.com 2023-04-05 17:11 出处:网络
I\'m working on a project in Lua where I will be creating tables and storing them in a master table, to be erased at a later time. I will pass around references to these tables to other sibling tables

I'm working on a project in Lua where I will be creating tables and storing them in a master table, to be erased at a later time. I will pass around references to these tables to other sibling tables.

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

The problem that occurs is that when I wish to erase the reference from the master table, the reference still remains in master[2] here. Obviously my first solution was to make the tables have weak values. (through .__mode on a metatable, not shown here)

This worked, and would work, so long as I would never store a singly-referenced table within these tables.

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

The third element, some_table would eventually be collected, because the tables have weak values, and this table (some_table) is not referenced anywhere else. This is undesired behavior. My latest solution involves creating "weak referen开发者_开发知识库ce objects" to the tables within the master table. A naive implementation follows:

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

These weak reference objects act similarly to boost::weak_ptrs and accomplish my goal, but I am uncertain if they are the best solution to my problem.

Is there a better way; a more elegant solution? Is my design, which requires this master table, perhaps flawed?


Given that:

  1. You want master to be the "one place" where you define whether an object exists or not
  2. Your objects can have links between them

Then probably the simplest architecture is reserving one of the members of each object as a "middle man" in charge of managing the references to others. Here're the steps:

  1. Make master a regular table (not weak)
  2. On each physical object, create a weak table called links (or whatever name suits your logic better)
  3. Make all links tables weak. Use them to store references to other objects.

And this is a possible implementation. I've tried it in 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")
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号