开发者

How to sync Lua and C++ garbage collection

开发者 https://www.devze.com 2023-04-01 20:54 出处:网络
I am trying to embed lua in an existing C++ application and have made a standard procedure for it by inheriting from a开发者_高级运维 class that does the work.

I am trying to embed lua in an existing C++ application and have made a standard procedure for it by inheriting from a开发者_高级运维 class that does the work. The serious problem I see is that if the exposed object gets deallocated or deleted in the C++ environment then a call from Lua will cause crashes. If the memory is being deleted by the program using 'delete' then I can maybe write a wrapper on delete to take care of deallocation in Lua as well, but if the memory was allocated by C++ and deallocated when the appropriate variable is out of scope I don't see a way on how to find that out and then take appropriate actions in the lua space, anybody has any ideas on this?

Thanks.


In general, virtually every Lua wrapper has some way to decide who owns what memory. That is, whether an object is owned by (and therefore will be deleted by) Lua or by your application.

If you have given Lua a pointer to an object that C++ owns, then you must find a way to ensure that Lua does not use this pointer past the point where C++ deletes it. There are several ways to avoid this. One way is to transfer ownership to Lua.

Another way is to use a boost/std::shared_ptr, which allows you to share ownership between C++ and Lua. If you're manually doing this, then you are creating some non-light userdata which is the size of a shared_ptr in Lua. You attach a cleanup metamethod to it that will destroy the shared_ptr, and you use placement-new to construct the shared_ptr on the Lua userdata. Luabind actually has this built-in as a feature: if you pass a shared_ptr to Lua, then they both share ownership of the memory.

You could also use a boost/std::weak_ptr. This is an object that you query to get a shared_ptr. The idea is that you're not supposed to keep the pointer around; you query it temporarily as needed, but you only store the weak_ptr permanently. If the object has lost all of its shared_ptr references, then querying the weak_ptr will return a null pointer.


You will have to use an RAII wrapper that can bind to the Lua instance using the registry and expose the values to Lua using a table- you can remove an internal pointer from it when you're done.

template<typename T> class LuaExposedValue {
    T t;
    lua_State* ls;
public:
    LuaExposedValue(lua_State* L) {
        // set registry[&t] = { &t }
        ls = L;
    }
    ~LuaExposedValue() {
        // remove &t from the table
    }
}

Alternatively, just ban Lua from accessing it after the variable is gone and let the scripter worry about it.

Finally, you could just allocate everything that Lua can access using the Lua GC.


Disclaimer: I wrote the library I'm about to recommend

You might want to try using this LuaWrapper Library that sounds like it'll handle what you're trying to do. It's not even really a library, it's just a single header file.

You can use luaW_push<MyType>(L, myObj); to push your objects into Lua. Lua will not own the objects you create from C++ unless you run luaW_hold<MyType> on them. In other words, unless you tell Lua to, it will not garbage collect your object.

Conversely, you can use MyType.new() in your Lua code to create an object, which Lua does own. It will be garbage collected as you would expect. If you want to pass ownership to C++ you can call luaW_release<MyType> on your object.

There's also functions like luaW_to<MyType> and luaW_check<MyType> and to a limited degree it correctly supports inheritance from base types (though at the moment it only allows for single inheritance). I find that this greatly simplifies my own attempts at using C++ and Lua together because it make managing pointer ownership very straightforward.

0

精彩评论

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