Lua weak references
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_ptr
s 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:
- You want master to be the "one place" where you define whether an object exists or not
- 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:
- Make
master
a regular table (not weak) - On each physical object, create a weak table called
links
(or whatever name suits your logic better) - 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")
精彩评论