【发布时间】:2021-05-04 06:09:37
【问题描述】:
我正在尝试通过 Lua 的 C API 向 Lua 公开一个简单的 C++ 类。我知道有些库已经解决了这个问题,但我想了解如何仅使用 C API 来解决此问题。
这是我的程序:
#define LUA_LIB
#include <cassert>
extern "C"
{
#include "lua.h"
#include "lauxlib.h"
}
namespace
{
class Foo
{
public:
Foo(int state)
: _state(state)
{}
int get_state() const
{ return _state; }
private:
int _state;
};
int foo_new(lua_State *L)
{
assert(lua_gettop(L) == 2);
luaL_checktype(L, 1, LUA_TTABLE);
lua_newtable(L);
lua_pushvalue(L, 1);
lua_setmetatable(L, -2);
lua_pushvalue(L, 1);
lua_setfield(L, 1, "__index");
int state = lua_tointeger(L, 2);
auto **__obj = static_cast<Foo **>(lua_newuserdata(L, sizeof(Foo *)));
*__obj = new Foo(state);
lua_setfield(L, -2, "__self");
return 1;
}
int foo_get_state(lua_State *L)
{
assert(lua_gettop(L) == 1);
luaL_checktype(L, 1, LUA_TTABLE);
lua_getfield(L, 1, "__self");
auto *__obj = static_cast<Foo *>(lua_touserdata(L, -1));
lua_pushinteger(L, __obj->get_state());
return 1;
}
luaL_Reg const foo_functions[] = {
{"new", foo_new},
{"get_state", foo_get_state},
{nullptr, nullptr}
};
} // namespace
extern "C"
{
LUALIB_API int luaopen_foo(lua_State *L)
{
luaL_newlib(L, foo_functions);
lua_setglobal(L, "Foo");
return 1;
}
} // extern "C"
foo_new 创建一个 Lua 表,该表将 C++ Foo 对象作为用户数据存储在其 __self 字段中。我将 Lua 中的这个函数称为local foo = Foo:new(1)。但是,这似乎可行,随后调用print(foo:get_state()) 不会返回1,而是返回一些垃圾值。为什么会这样,我该如何解决?
【问题讨论】:
-
1.您在
new中分配内存auto **__obj,但在foo_get_state中访问为auto *__obj。 2. 这样的分配在垃圾回收对象后导致内存泄漏 -new Foo()永远不会被释放(检查stackoverflow.com/questions/519808/… 如何在不分配额外内存的情况下访问构造函数) -
foo_get_state中的代码必须是:auto **__obj = static_cast<Foo **>(lua_touserdata(L, -1)); lua_pushinteger(L, (*__obj)->get_state());,不要忘记检查指针是否有效。 -
@Darius:好的,除了内存泄漏之外,我还混淆了
**__obj和*__obj。我现在刚刚用auto *__obj = new (lua_newuserdata(L, sizeof(Foo))) Foo(state);替换了分配步骤。 Lua 代码现在输出一个,但似乎仍然没有调用~Foo?除此之外,如果您将您的 cmets 组合成一个答案,我会接受它。