繁体   English   中英

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

[英]How to extract C++ object pointer from Lua

我在C ++中有一个叫做“ Point”的类:

class Point
{
public:
  int x, y;

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

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

这是我(目前无法正常工作)的尝试,希望可以弄清我到底要做什么。 请注意,这段代码本质上是本教程中的修改后的复制/粘贴,并且我正在使用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(期望的点,得到了表)”行:checkPoint()函数内部的ud = luaL_checkudata(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;
// ...

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

为此,您可以如下扩展代码:

  • 在userdata gc上编写一个由lua调用的deletePoint函数。

     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} }; 

我建议您不要编写自己的绑定,而要使用经过测试并证明有据的 绑定 ,例如luabridgeluabind

您的绑定将减少为:

getGlobalNamespace (L)
    .beginClass<Point>("Point")
     .addConstructor<void (*) (int,int)>()
     .addData("X", &Point::x)
     .addData("Y", &Point::y)
    .endClass()
;

和你的lua看起来像

local point = Point(10,20)

与luabridge。

有关提取值的信息,请参见例如luabridge中的LuaRef 如果使用c ++ 11,则还有其他一些非常漂亮的lua绑定库。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM