【问题标题】:lua userdata pass by valuelua userdata 按值传递
【发布时间】:2016-02-05 01:43:21
【问题描述】:

我相信你们中的一些人可能会遇到这个问题。我有一个名为矩阵的用户数据对象,它是用 C++ 编写的,具有运算符重载的常用方法,例如。

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

在 C++ 中,当我创建两个矩阵时说 AB 并创建 A=B 然后 A 和 B 可以用作两个独立的对象。但是,在 Lua 中,当我编写 A=B 并更改 B 的任何属性时,A 也会更改。

很明显,从 Lua 手册中也可以看出,Lua 通过引用来分配用户数据,这解释了上述行为。但是,我怎样才能让A=B 按值传递,以便B 更改时A 不受影响。

事实上,我想让赋值A=B通过引用传递,这确实非常快并且Matlab可以做到,但是当我第一次设置B的属性时,我想要@987654333 @ 是独立创建的,这是我的 Matlab 练习的,因为我可以从 Matlab 的内存使用情况中跟踪。

如果这是可能的,它是在 C++ 中完成的还是在 lua 包装器代码中的某个地方完成的?任何示例代码都会很棒。

编辑 1:这是我的想法,我不确定它是否会起作用或者是否足够快

typedef struct luaelement
{
   int type;
   std::string name;
   void* addr; //newly added field
   bool isRef;  //newly added
} 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);
    //How can I get the address, maybe a metamethod named 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 表中的所有变量。我计划通过检查void* 地址来实施并查看是否存在对现有用户数据变量的任何引用。我不确定这是否真的有效,以及在性能方面是否值得付出努力。

【问题讨论】:

  • 你的最后一部分是一个严格的 C++ 问题;你所说的被称为“写时复制”语义。除非您的矩阵对象很大,否则对于值类型通常是一个糟糕的主意。当然,它听起来很快。但是使用现代移动语义和复制省略,您会发现自己并没有做太多的对象复制。它还使您的对象非常非线程安全,或者需要您锁定互斥锁才能访问它们。
  • "如何让 A=B 按值传递,这样当 B 改变时 A 不受影响。" - 这就像问“我怎样才能让MyClass c = new MyClass(); 在 C++ 中像在 Java 中一样工作?” - 即使你可以(我认为你不能),这也不是一个好主意。
  • 我只需要一种方法来克隆它。
  • @warspyking:这正是我在阅读完所有 cmets 后打算做的事情。

标签: c++ lua


【解决方案1】:

但是,我怎样才能让 A=B 按值传递,以便 B 更改时 A 不受影响。

你不能。

记住:Lua 是动态类型的。因此,虽然 AB 现在恰好存储了您的矩阵类型,但以后再转到 A = 1 就很好了。现在,A 存储一个整数。

C++ 和 Lua 是非常不同的语言。在 C++ 中,变量要么是对象,要么是对对象的引用(指针是指针类型的对象)。每个变量将永远只保存它开始的对象。存储在该对象中的值可以更改,但对象本身存在并且具有由相关变量的生命周期定义的生命周期。

在 Lua 中,变量只是一个可以存储对象的盒子。该盒子与它当前恰好存储的对象没有关系;任何盒子都可以容纳任何物体。在任何时候,您都可以将那个盒子里的东西与任何其他盒子里的对象交换。

您不能干预将一个变量复制到另一个变量(通常。您可以进行元表操作,但这仅适用于该表的成员。局部变量永远不会受到影响)。这就是 Lua 作为一种语言的工作方式。 C++ 变量是对象; Lua 变量是存储箱。最好接受不能在 Lua 中编写 C++ 风格的代码,而是专注于在 Lua 中编写 Lua 风格的代码。

所以如果你想创建一个对象的副本,你必须显式地创建一个对象的副本


这是我的想法,我不确定它是否会起作用或者是否足够快

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

首先,您将元表应用于全局表本身,这通常是……粗鲁的。

其次,即使您的代码有效,它也不适用于像这样简单的事情:

globalVar = {}  --Perfectly legal to set a table inside the global table.
globalVar.value = A
globalVar.value = B  --Will not alert your copying code.

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

停止尝试将 Lua 变成它不是的东西。使用您拥有的语言,而不是您想要的语言。

【讨论】:

  • Lua 中的表和函数以及用户数据由变量引用。然而,数字、字符串、布尔值和 nil 由变量保存
  • @NicolBolas:感谢您的 cmets,尤其是最后一句“您拥有,而不是您想要的语言”:-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-25
  • 2011-06-22
  • 1970-01-01
  • 2016-10-22
  • 2012-01-16
  • 2012-10-14
相关资源
最近更新 更多