2016-02-05 53 views
1

我相信你们中的一些人可能会遇到这个问题。我有一个用C++编写的叫做矩阵的用户数据对象,通常使用运算符重载方式,比如。lua userdata按值传递

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通过引用来解释上述行为来做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; //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*地址来实现并查看是否存在对现有userdata变量的引用。我不确定这是否真的有效,如果值得在性能方面付出努力。

+0

你最后的部分是严格的C++问题;你在谈论什么叫做“写时复制”语义。除非你的矩阵对象很大,否则对于一个值类型通常是一个糟糕的主意。当然,它听起来很快。但随着现代移动语义和复制elision,你会发现自己没有做太多的对象复制。它也使得你的对象非线程安全,或者需要你锁定互斥锁来访问它们。 –

+2

“如何让A = B按值传递,以便在B发生变化时A不受影响。” - 这就像问:“我怎样才能让MyClass c = new MyClass();'在C++中工作,就像它在Java中一样?” - 即使你可以(而且我认为你不能),这不是一个好主意。 – immibis

+0

我只是有一个方法克隆它的矩阵。 – warspyking

回答

4

但是,如何让A = B按值传递,以便在B发生变化时A不受影响。

你不能。

记住:Lua是动态输入。所以虽然AB恰好现在存储您的矩阵类型,但稍后去A = 1也是很好的。现在,A存储一个整数。

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

在Lua中,变量只是一个对象可以存储在其中的框。该框与它当前碰巧存储的对象没有关系;任何箱子可以容纳任何物体。并且在任何时候,您都可以将该框中的内容与其他框中的对象进行交换。

你不能干涉将一个变量拷贝到另一个变量中(通常,你可以做metatable体操,但只适用于该表的成员,局部变量永远不会受到影响)。这就是Lua如何作为一种语言工作的。C++变量是对象; Lua变量是存储盒。最好接受你不能在Lua中编写C++风格的代码,而是专注于在Lua中编写Lua风格的代码。

所以,如果你想创建一个对象的副本,你必须创建该对象的副本明确


这里是我的想法,我不知道这是否会在所有的工作,或者如果这样足够

快,不会有几个原因的工作。

首先,你正在应用metatable到全局表本身,这通常是...粗鲁。

其次,即使你的代码工作,它不会对如此简单的东西的工作:

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变成它不是的东西。使用你有的语言,而不是你想要的语言。

+0

可能最好的方法是添加一个拷贝metamethod ... – macroland

+0

Lua中的表和函数和userdatas被一个变量引用*。数字,字符串,布尔值和零,然而*持有*变量。 – warspyking

+0

@macroland:那不行。 –