gpt4 book ai didi

c++ - 如何从 Lua 中提取 C++ 对象指针

转载 作者:可可西里 更新时间:2023-11-01 16:31:06 26 4
gpt4 key购买 nike

我在 C++ 中有一个名为“Point”的类:

class Point
{
public:
int x, y;

//constructor
Point(int x, int y)
{
this->x = x;
this->y = y;
}
};

我的目标是能够用 Lua 脚本实例化一个 Point 对象,并从 Lua 堆栈中提取指向该对象的指针。

这是我(目前没有工作)的尝试,希望能澄清我到底想做什么;请注意,此代码实质上是从 this tutorial 中修改复制/粘贴的并且我正在使用 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)

运行此代码,我收到以下错误:“错误参数 #3(预期点,得到表)”在行中: ud = luaL_checkudata(L, index, "Point") 在 checkPoint() 函数内。

如果有人能引导我朝着正确的方向前进,我将不胜感激。

最佳答案

您在上述使用和绑定(bind)中存在一些问题。

在你的测试脚本中,local point 不会被您的宿主 c++ 程序看到。这是因为,嗯,它是该脚本的本地内容。如果你想从 C++ 访问它,要么返回 point作为脚本中的值或使其成为全局值并使用 lua_getglobal(L, "point") 检索它.

checkPoint函数有一些不必要的代码。如果你看另一个luaL_check* Lua C API 提供的函数,它们主要检查堆栈索引处的给定值是否是正确的类型。如果是,则将该类型转换为 C++ 可以使用的类型。

所以在你的“checkPoint”函数中你真正需要做的是:

Point* checkPoint(lua_State* L, int index)
{
return *((Point **) luaL_checkudata(L, index, "Point"));
}

如果您将脚本更改为此,例如:

local point = Point.new(10,20)
return point

您应该能够访问 point从 C++ 以下列方式:

// ...
luaL_dofile(L, "testz.lua");

Point *foo = checkPoint(L, -1);
std::cout << "x: " << foo->x << " y: " << foo->y;
// ...

另一个重点是关于暴露给 lua 的 C++ 对象生命周期。因为每当 Point.new 时,您都在使用 C++“new”运算符进行分配和构造。从脚本中调用,您是在间接说让 lua 处理这个暴露的 C++ 对象的生命周期。这意味着您还需要实现 __gc元方法充当“终结器”或非确定性析构函数。没有这个你就没有办法“删除” point对象并在lua垃圾回收对应的userdata时回收空间。

为此,您可以按如下方式扩充代码:

  • 写一个deletePoint lua 在用户数据 gc 上调用的函数。

    static int deletePoint(lua_State *L)
    {
    Pointer **p = checkPoint(L, 1);
    delete *p;
    *p = NULL; // probably not needed but to be safe
    return 0;
    }
  • 将其添加到您的 pointFuncs所以 lua 知道它。

    static const luaL_Reg pointFuncs[] =
    {
    {"new", newPoint},
    {"__gc", deletePoint},
    {NULL, NULL}
    };

关于c++ - 如何从 Lua 中提取 C++ 对象指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18261891/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com