lua C api:类访问器

时间:2016-06-07 14:14:18

标签: c++ lua

我已经实现了一个lua包装器来使用lua中的userdata来访问C ++类:http://lua-users.org/wiki/BindingWithMembersAndMethods

我的C ++类看起来像这样:

class GameObject
{   
public:
    GameObject();
    ~GameObject();

    int             m_id;
    float           m_scale;
    const char*     m_path;
};

到目前为止,我可以在lua中执行此操作:

gameObject = GameObject.new()
gameObject.path = "test"
gameObject.scale = 2
local path = gameObject.path
local scale = gameObject.scale
print(scale)
print(path)

除了打印路径变量时,一切正常:

console output

“set string”行来自我在setter函数中输入的调试:

int LuaGameObjectManager::set_string (lua_State *L, void *v)
{
    v = (void*)luaL_checkstring(L, 3);
    std::cout << "set string : " << (char*) v << std::endl; 
    return 0;
}

所以我想我正在设置正确的值,并且在使用此getter函数获取它时必须出现问题:

int LuaGameObjectManager::get_string (lua_State *L, void *v)
{
    char * tmp = (char*)v;
    lua_pushstring(L, tmp );
    return 1;
}

这就是我如何定义我的方法和metatable:

static const luaL_Reg methodsArray[] = {
    {"new",        New},
    {"load",       load},
    {0,0}
};

static const luaL_Reg metaArray[] = {
    {"__gc",       gc},
    {"__tostring", toString},
    {0, 0}
};

static LuaManager::Xet_reg_pre gettersArray[] = {
    {"scale",       get_int,    offsetof(GameObject, m_scale)   },
    {"path",        get_string, offsetof(GameObject, m_path)   },
    {0,0}
};

static LuaManager::Xet_reg_pre settersArray[] = {
    {"scale",       set_int,    offsetof(GameObject, m_scale)   },
    {"path",        set_string, offsetof(GameObject, m_path)   },
    {0,0}
};

那么有没有人知道为什么我会打印一些奇怪的值?这是编码问题吗? 我知道你们需要更多的代码来理解我的问题并帮助我,但是整个部分注册lua方法和metatable很长,所以只需告诉我你希望我发布的代码。

1 个答案:

答案 0 :(得分:2)

我可以看到两个问题。

  1. 在函数内部分配(原始)局部变量对外界没有影响。

    int LuaGameObjectManager::set_string (lua_State *L, void *v)
    {
        v = (void*)luaL_checkstring(L, 3);
    

    v这里是一个局部变量,所以这不会改变set_string方法之外的任何内容。对象的内存布局如下所示:

                  v
                   \
    |  int  | float |pointer|
                        \
                         |c|c|c|c|c|...
    

    所以,你可能想要类似于

    的东西
    *((char**)v) = luaL_checkstring(L, 3);
    

    但请注意,luaL_checkstring返回的字符串由Lua管理,并且可以在任何时候进行垃圾收集,因此您应该复制它(并且您必须清除以前的值{ {1}}或者你会得到内存泄漏)。我会把详细信息留给你......

  2. 您发布的m_path方法(以及您在链接的Wiki文章中使用的方法)假设它正在处理内联字符数组。

    get_string

    您的情况不同,因为您使用指向字符数组的第一个元素的指针(参见上文)。正确的实现方式如下:

                  v
                   \
    |  int  | float |c|c|c|c|c|...
    

    在这种情况下,int LuaGameObjectManager::get_string (lua_State *L, void *v) { lua_pushstring(L, *((char**)v)); return 1; } 已经为您制作了一份副本(最终将由Lua进行垃圾收集),因此您不必考虑这一点。