lua userdata 传值问题

我确信有些人可能会遇到这个问题。我有一个名为矩阵的 C++ userdata 对象,具有常规的运算符重载方式,例如。

CMatrix<T>& operator=(const CMatrix<T>& b);
CMatrix<T>& operator=(const T& rhs);

在 C++ 中,当我创建两个矩阵 A 和 B 并使 A=B 时,A 和 B 可以作为两个独立的对象使用。然而,在 Lua 中,当我写下 A=B 并改变 B 的任何属性时,A 也会改变。

显然,从 Lua 手册中可以看出,Lua 通过引用进行 userdata 赋值,这就解释了上述行为。但是,我该如何使 A=B 传递值,以便当 B 更改时 A 不受影响。

事实上,我想使赋值 A=B 传递引用,这确实非常快,Matlab 也是这样做的,但是当我第一次设置 B 的某个属性时,我希望创建独立的 B,这就是 matlab 所使用的方式,我可以从 matlab 的内存使用情况中跟踪到这一点。

如果这是可能的,是在 C++ 中还是在 lua 封装代码的某个地方完成的?任何示例代码都将非常好。

编辑1:这是我的想法,我不确定它是否会完全工作或是否足够快

typedef struct luaelement
{
   int type;
   std::string name;
   void* addr; //新增字段
   bool isRef;  //新增
} luaelement;

glbLuaElementSet=new set<luaelement,comparenocaseforluaelement>();

int l_newindex(lua_State* L)
{
    luaelement element;
    const char* key=lua_tostring(L,-2);
    string str=key;
    element.name=key;
    element.type=lua_type(L,-1);
    // 我如何得到地址,也许是一个名为 address 的元方法
    glbLuaElementSet->insert(element);
    lua_rawset(L,1);
}

void l_registermetamethod(lua_State* L)
{
    lua_getglobal(L,"_G");
    lua_createtable(L, 0, 1);
    lua_pushcfunction(L, l_newindex);
    lua_setfield(L, -2, "__newindex");
    lua_setmetatable(L, -2);
}

现在,借助 glbLuaElementSet 变量和 l_newindex 元方法,我可以跟踪所有插入到全局 _G 表中的变量。我计划实现并查看是否存在对已有 userdata 变量的任何引用,通过检查 void* 地址来实现。我不确定这是否真的会起作用,以及在性能方面是否值得付出努力。

点赞
用户734069
用户734069

你不能。

记住:Lua 是动态类型语言。因此,虽然 AB 目前存储的是矩阵类型,但稍后写成 A = 1 同样是合法的,此时 A 存储了一个整数。

C++ 和 Lua 是非常不同的语言。在 C++ 中,变量要么是对象,要么是对象的引用(指针是指针类型的对象)。每个变量只会一直保存它所起始的对象。其中存储的值可以改变,但对象本身存在,并且其生存期由相应变量的生存期定义。

在 Lua 中,变量只是对象可以存储在的盒子。该盒子与其当前所存储的对象没有任何关系,任何盒子都可以存储任何对象。并且在任何时候,你可以将该盒子中的内容与任何其他盒子中的对象进行交换。

你不能干涉将一个变量复制到另一个变量中(通常情况下如此。你可以进行元表操作,但这仅适用于该表的成员。局部变量不会受到影响)。这只是 Lua 作为一种语言的运作方式。C++ 变量是对象;Lua 变量是存储盒子。最好接受无法在 Lua 中编写 C++ 风格代码的事实,而是专注于在 Lua 中编写 Lua 风格代码。

因此,如果你想复制一个对象的副本,必须明确地创建该对象的副本。


这是我的想法,我不确定它是否会生效,如果生效是否足够快

由于多种原因,它不起作用。

首先,你正在将元表应用到全局表本身,这通常是...不礼貌的。

其次,即使你的代码可以运行,它也无法处理这种简单情况:

globalVar = {}  -- 在全局表中设置一个表是完全合法的。
globalVar.value = A
globalVar.value = B  -- 不会触发你的复制代码。

__newindex 元方法是不递归的。它无法在表的层次结构中上下遍历。因此,存储在全局表中的表仍然可以更改其成员。

停止试图将 Lua 变成它不是的东西。与你拥有的语言一起工作,而不是你想要的语言。

2016-02-05 02:03:40