lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


If I'm understanding right, the situation you have is you've got a C data structure `mylist` which needs to own (or at least, hold a reference to) a Lua value (the `mylistitem`). Then on top of that `mylist` is also owned by Lua as a userdata but we can ignore that as it doesn't really affect the scenario.

The only way to make that work is for `mylist` to create a reference to the `mylistitem` Lua value in the implementation of insertitem() and for `mylist` to keep track of that reference (as well as potentially the raw pointer for convenience).

One way to do that is by using luaL_ref to give you effectively an integer handle to the `mylistitem`. And when the item is removed from the list, you luaL_unref() it. That works for a lot of scenarios although might have some performance scaling issues if the data structures are used heavily. For something as generic as a container class you might want to use a dedicated Lua table for each `mylist` and insert the `mylistitem` into that table using lua_rawseti or similar. You'll then maybe have to use something like luaL_ref to keep track of that table, of course.

Regards,

Tom

> On 25 Nov 2023, at 14:22, Andreas Falkenhahn <andreas@falkenhahn.com> wrote:
> 
> I'm working on a Lua binding for a C library where each object allocated by the C library is stored as a Lua userdata object with a metatable that handles method calls for the object and also adds a __gc function for the garbage collector so that the C object is deleted as soon as there are no more references to it in the Lua script. This basically works but I'm wondering what the best way to solve the problem of garbage collection is in this case?
> 
> For example, consider the situation where the C library is used to allocate a list and list items. The C code looks something like this:
> 
> static int alloclist(lua_State *L)
> {
> struct mylist *p = lua_newuserdata(L, sizeof(mylist));
> setmetatable(...);
> p->obj = alloc_the_list();
> return 1;
> }
> 
> static int alloclistitem(lua_State *L)
> {
> struct mylistitem *p = lua_newuserdata(L, sizeof(mylistitem));
> setmetatable(...);
> p->obj = alloc_the_list_item();
> return 1;
> }
> 
> Now imagine the following situation in a Lua script:
> 
> local list = alloclist()
>       local listitem = alloclistitem()
>       list:insertitem(listitem)
>       listitem = nil
> 
> Now "listitem" is marked for garbage collection even though it is still referenced by "list" because it has been inserted into the list using "list:insertitem()". 
> 
> The only way I see to solve this is to not use userdata at all but allocate custom memory for each object and implement a separate free() method that has to be explicitly called when the script is done with an object. Or is there a better way to do this?
> 
> -- 
> Best regards,
> Andreas Falkenhahn                          mailto:andreas@falkenhahn.com