简体   繁体   中英

lua userdata pass by value

I am sure some of you might run into this problem. I have a userdata object called matrix written in C++ with usual ways of operator overloading, such as.

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

In C++ when I create two matrices say A and B and make A=B then A and B can be used as two independent objects. However, in Lua when I write A=B and change any property of B , then A changes as well.

It is apparent and also from the Lua manual it is said that Lua makes the assignment of userdata by reference which explains the above mentioned behaviour. However, how can I make A=B to pass by value so that when B changes A is not affected.

As a matter of fact, I want to make the assignment A=B pass by reference which is indeed very fast and which Matlab does, but when I set a property of B for the first time, I want B to be created independently which is practiced my Matlab as I could have tracked from memory usage of Matlab.

If this is possible, is it done inside C++ or somewhere in the lua wrapper codes? Any example code would be great.

EDIT 1: Here is my idea, I am not sure if it will work at all or if so fast enough

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);
}

Now with the glbLuaElementSet variable and l_newindex metamethod I can track all the variables inserted at global _G table. I was planning to implement and see if any reference to already existing userdata variable is in place by checking the void* address. I am not sure if this will really work and if it is worth the effort in terms of performance.

However, how can I make A=B to pass by value so that when B changes A is not affected.

You can't.

Remember: Lua is dynamically typed . So while A and B happen to store your matrix type right now, it's perfectly fine to later go A = 1 . Now, A stores an integer.

C++ and Lua are very different languages. In C++, variables are either objects or references to objects (pointers are objects of pointer type). Each variable will only ever hold the object that it starts with. The value stored in that object can be changed, but the object itself exists and has a lifetime defined by the lifetime of the variable in question.

In Lua, a variable is just a box that objects can be stored in. That box has no relationship to the object that it currently happens to store; any box can hold any object. And at any time, you can swap what's in that box with the object from any other box.

You cannot interfere in the copying of one variable into another (generally. You could do metatable gymnastics, but that would only apply to members of that table. Local variables would never be affected). This is simply how Lua works as a language. C++ variables are objects; Lua variables are storage boxes. It's best to accept that you can't write C++-style code in Lua, and instead focus on writing Lua-style code in Lua.

So if you want to create a copy of an object, you have to create a copy of that object explicitly .


Here is my idea, I am not sure if it will work at all or if so fast enough

It will not work for several reasons.

First, you're applying a metatable to the global table itself, which is typically... rude.

Second, even if your code worked, it wouldn't work for something as simple as this:

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

The __newindex metamethod is not recursive . It can't walk up and down the hierarchy of tables. So a table stored within the global table can still have its members changed.

Stop trying to make Lua into something it isn't. Work with the language you have, not the language you want.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM