如何提取C++;来自Lua的对象指针 我在C++中有一个叫做“点”的类:

如何提取C++;来自Lua的对象指针 我在C++中有一个叫做“点”的类:,c++,lua,C++,Lua,我的目标是能够用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(

我的目标是能够用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;
 }
运行此代码时,我在行中得到以下错误:“错误参数#3(预期为点,得到表)”: ud=checkPoint()函数中的luaL_checkudata(L,索引,“点”)


如果有人能给我指引正确的方向,我将不胜感激。

我建议不要编写自己的绑定,而是使用经过测试和记录的绑定,例如或

您的绑定将减少到:

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


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

在上述使用和绑定中存在一些问题

<>你的测试脚本,本地点> /CUT>不会被主机C++程序看到。这是因为,嗯,它是该脚本的本地版本。如果您希望它从C++访问,则返回<代码>点<代码>作为脚本的值,或者使其成为全局的,并使用<代码> LuaGigGlobal(L,“PoT”)< /C> > /<
checkPoint
函数包含一些不必要的代码。如果您查看luaapi提供的其他
luaL\u check*
函数,它们主要检查堆栈索引处的给定值是否是正确的类型。如果是,则将该类型转换为C++可以使用的。 因此,在“检查点”功能中,您真正需要做的是:

Point* checkPoint(lua_State* L, int index)
{
  return *((Point **) luaL_checkudata(L, index, "Point"));
}
如果将脚本更改为此,例如:

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

C++,您可以通过以下方式访问<代码>点<代码>:

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

Point *foo = checkPoint(L, -1);
std::cout << "x: " << foo->x << " y: " << foo->y;
// ...
  • 将它添加到您的
    pointFuncs
    中,以便lua了解它

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

  • 我一定会查看luabind。然而,作为一种学习经验,我确实希望能让它发挥作用。不幸的是,即使在我在Lua代码中切换到冒号操作符并在newPoint()函数中更改参数检查之后,我仍然会遇到与以前相同的错误。你知道这是为什么吗?我更新了我的答案,因为我没有一个实际的解释,而greatwolf有explain@user2687268我已经添加了一个关于处理userdata clean的注释。这是一个很好的解释,但是它似乎假设在点指针从lua状态获取点之前,垃圾收集器不会运行。这个简单的例子可能不是这样,但在更复杂的脚本中,您将不知道gc何时删除您的点。因此,绑定库中的内存生存期管理就变得非常复杂。典型的解决方案之一是将对象包装在引用计数对象中,这样垃圾回收器调用只在C++没有引用时释放内存,反之亦然,如果您删除C++对象上的包装对象,如果原始对象仍然作为用户数据生存,内存应该由垃圾收集器释放。
    local point = Point.new(10,20)
    return point
    
    // ...
    luaL_dofile(L, "testz.lua");
    
    Point *foo = checkPoint(L, -1);
    std::cout << "x: " << foo->x << " y: " << foo->y;
    // ...
    
    static int deletePoint(lua_State *L)
    {
      Pointer **p = checkPoint(L, 1);
      delete *p;
      *p = NULL;  // probably not needed but to be safe
      return 0;
    }
    
    static const luaL_Reg pointFuncs[] =
    {
      {"new", newPoint},
      {"__gc", deletePoint},
      {NULL, NULL}
    };