如何获取从C++传递到Lua函数的表格更新值并同步到std::vector?
解决C++ std::vector与Lua Table的双向同步问题
咱们先明确一个关键点:Lua的table和C的std::vector<float>是完全独立的内存对象,**没法像C引用那样直接传递**——你把vector的值复制到Lua table里之后,Lua修改table根本不会自动同步回C++的vector,必须手动把修改后的table数据写回去。下面给你两种可行的实现方案:
方案一:让Lua函数返回修改后的Table(代码更简洁)
这种方式需要稍微修改Lua函数,让它返回处理后的table,然后在C++里读取这个返回值更新vector。
修改后的Lua代码
function myFunc(t) for i=1, #t do t[i] = t[i] * 2 end return t -- 返回修改后的table,方便C++读取 end
更新后的C++代码
void myFunc(lua_State *L, std::vector<float> &vec) { // 1. 把Lua的myFunc函数压入栈 lua_getglobal(L, "myFunc"); // 2. 创建Lua table并填充vector的值 lua_newtable(L); for (size_t i = 0; i < vec.size(); ++i) { lua_pushinteger(L, i + 1); // Lua索引从1开始 lua_pushnumber(L, vec[i]); lua_settable(L, -3); // 将键值对存入table(-3是当前table在栈中的位置) } // 3. 调用Lua函数:1个参数,1个返回值,0表示使用默认错误处理 if (lua_pcall(L, 1, 1, 0) != 0) { std::cout << "Error : Failed to call myFunc: " << lua_tostring(L, -1) << std::endl; lua_pop(L, 1); // 弹出栈中的错误信息 return; } // 4. 从栈顶取出返回的table,同步回C++ vector vec.clear(); size_t table_len = lua_rawlen(L, -1); // 获取table的长度 for (size_t i = 1; i <= table_len; ++i) { lua_pushinteger(L, i); lua_gettable(L, -2); // 获取table[i]的值,此时栈顶是该值 if (lua_isnumber(L, -1)) { vec.push_back(static_cast<float>(lua_tonumber(L, -1))); } lua_pop(L, 1); // 弹出当前值,准备下一次循环 } lua_pop(L, 1); // 弹出栈中的table }
方案二:用Lua注册表存储Table(无需修改原有Lua代码)
如果不想修改已有的Lua函数,可以把创建的table存入Lua的注册表,调用完Lua函数后再从注册表取出table同步数据。
原Lua代码保持不变
function myFunc(t) for i=1, #t do t[i] = t[i] * 2 end end
对应的C++代码
void myFunc(lua_State *L, std::vector<float> &vec) { // 1. 压入Lua函数myFunc lua_getglobal(L, "myFunc"); // 2. 创建并填充table lua_newtable(L); for (size_t i = 0; i < vec.size(); ++i) { lua_pushinteger(L, i + 1); lua_pushnumber(L, vec[i]); lua_settable(L, -3); } // 3. 复制table并存入注册表,获取引用ID lua_pushvalue(L, -1); // 复制当前栈顶的table int table_ref = luaL_ref(L, LUA_REGISTRYINDEX); // 将table存入注册表,返回引用ID // 4. 调用Lua函数:1个参数,0个返回值 if (lua_pcall(L, 1, 0, 0) != 0) { std::cout << "Error : Failed to call myFunc: " << lua_tostring(L, -1) << std::endl; lua_pop(L, 1); luaL_unref(L, LUA_REGISTRYINDEX, table_ref); // 释放注册表中的引用 return; } // 5. 从注册表取出修改后的table lua_rawgeti(L, LUA_REGISTRYINDEX, table_ref); // 6. 同步table数据回vector vec.clear(); size_t table_len = lua_rawlen(L, -1); for (size_t i = 1; i <= table_len; ++i) { lua_pushinteger(L, i); lua_gettable(L, -2); if (lua_isnumber(L, -1)) { vec.push_back(static_cast<float>(lua_tonumber(L, -1))); } lua_pop(L, 1); } // 7. 清理资源 lua_pop(L, 1); luaL_unref(L, LUA_REGISTRYINDEX, table_ref); // 释放注册表引用 }
调用测试
不管用哪种方案,你的调用代码都可以保持不变:
std::vector<float> vec = {1,2,3,4,5}; myFunc(L, vec); // 此时vec的值会变成{2,4,6,8,10}
核心逻辑就是:Lua和C的内存空间是隔离的,数据传递本质是复制,所以修改后必须手动把Lua侧的数据写回C侧的vector。
内容的提问来源于stack exchange,提问作者Zack Lee
相关产品推荐
相关产品推荐

