如何在Lua中提取C++对象指针
我有一个名为“Point”的 C++ 类:
class Point
{
public:
int x, y;
//constructor
Point(int x, int y)
{
this->x = x;
this->y = y;
}
};
我希望能够使用 Lua 脚本实例化一个 Point 对象,并从 Lua 栈中提取指向此对象的指针。
以下是我(目前不起作用的)尝试,希望能够澄清我正在尝试做什么;请注意,此代码实际上是从 [这个教程](http://loadcode.blogspot.com/2007/02/wrapping-c-classes-in-lua.html)中复制/粘贴修改的,我使用 Lua 5.2:
static int newPoint(lua_State *L)
{
int n = lua_gettop(L);
if (n != 2)
return luaL_error(L, "expected 2 args for Point.new()", n);
// Allocate memory for a pointer to object
Point **p = (Point **)lua_newuserdata(L, sizeof(Point *));
double x = luaL_checknumber (L, 1);
double y = luaL_checknumber (L, 2);
//I want to access this pointer in C++ outside this function
*p = new Point(x, y);
luaL_getmetatable(L, "Point"); // Use global table 'Point' as metatable
lua_setmetatable(L, -2);
return 1;
}
static const luaL_Reg pointFuncs[] = {
{"new", newPoint},
{NULL, NULL}
};
//register Point to Lua
void registerPoint(lua_State *L)
{
lua_createtable(L, 0, 0);
// Register metatable for user data in registry
luaL_newmetatable(L, "Point");
luaL_setfuncs(L, pointFuncs, 0);
lua_pushvalue(L,-1);
lua_setfield(L,-2, "__index");
lua_setglobal(L, "Point");
}
Point* checkPoint(lua_State* L, int index)
{
void* ud = 0;
luaL_checktype(L, index, LUA_TTABLE);
lua_getfield(L, index, "__index");
ud = luaL_checkudata(L, index, "Point");;
return *((Point**)ud);
}
int main()
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
registerPoint(L);
luaL_dofile(L, "testz.lua");
lua_getglobal(L, "Point");
Point *foo = checkPoint(L, lua_gettop(L));
std::cout << "x: " << foo->x << " y: " << foo->y;
lua_close(L);
return 0;
}
下面是 Lua 脚本:
local point = Point.new(10,20)
运行此代码,我得到以下错误:“bad argument #3(Point expected, got table)”,该错误位于 checkPoint() 函数中的行 lua_lcheckudata(L, index, "Point")。
如果有人能引导我走向正确的方向,我将不胜感激。
在您上述的用法和绑定中存在一些问题。
在您的测试脚本中,local point 不会被主机的 C++ 程序看到。这是因为它只是该脚本的本地变量。如果您希望从 C++ 中访问它,可以通过将 point 作为脚本的返回值或使其全局并使用 lua_getglobal(L, "point") 检索它。
checkPoint 函数中有一些不必要的代码。如果您查看 Lua C API 提供的其他 luaL_check* 函数,它们主要检查栈索引处给定值的类型是否正确。如果是,就将该类型转换为 C++ 可以使用的内容。
因此,在您的 'checkPoint' 函数中,您只需要做的是:
Point* checkPoint(lua_State* L, int index)
{
return *((Point **) luaL_checkudata(L, index, "Point"));
}
例如,如果您将脚本更改为:
local point = Point.new(10,20)
return point
您应该可以按以下方式从 C++ 中访问 point:
// ...
luaL_dofile(L, "testz.lua");
Point *foo = checkPoint(L, -1);
std::cout << "x: " << foo->x << " y: " << foo->y;
// ...
另一个重要的观点是关于将 C++ 对象公开给 Lua 时的 C++ 对象生命周期。因为您每当从脚本调用 Point.new 时都会使用 C++ 的 'new' 进行分配和构造,这意味着您间接地说“让 Lua 处理这个公开的 C++ 对象的生命周期”。这意味着您还需要实现一个 __gc 元方法作为 'finalizer' 或非确定性析构函数。如果没有这个函数,您将无法 '删除' point 对象并在 Lua 垃圾回收相应的用户数据时回收空间。
为了实现这一点,您可以按如下方式修改代码:
写一个
deletePoint函数,当用户数据垃圾回收时由 Lua 调用。static int deletePoint(lua_State *L) { Pointer **p = checkPoint(L, 1); delete *p; *p = NULL; // 可能不需要,但为了安全起见 return 0; }将其添加到您的
pointFuncs中,这样 Lua 就知道它了。static const luaL_Reg pointFuncs[] = { {"new", newPoint}, {"__gc", deletePoint}, {NULL, NULL} };
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
我建议不要写自己的绑定程序,而是使用经过测试和文档化的绑定程序,例如 luabridge 或 luabind。
你的绑定将被简化为:
getGlobalNamespace (L) .beginClass<Point>("Point") .addConstructor<void (*) (int,int)>() .addData("X", &Point::x) .addData("Y", &Point::y) .endClass() ;使用 luabridge 后,你的 Lua 将如下所示:
local point = Point(10,20)有关提取值的示例,请参见 luabridge 中的 LuaRef。如果您使用 c++11,还有其他一些相当美丽的 Lua 绑定库。