Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/lua/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ Lua,c++;和消失的元表_C++_Lua_Metatable - Fatal编程技术网

C++ Lua,c++;和消失的元表

C++ Lua,c++;和消失的元表,c++,lua,metatable,C++,Lua,Metatable,背景 我和Watusimoto一起做游戏。我们使用一个LuaReAPPER的变体将我们的C++对象与游戏中的Lua对象连接起来。我们还使用一种称为Lua的变体来加速向量运算 一段时间以来,我们一直在努力解决一个我们无法解决的bug。将发生随机崩溃,这表明元表已损坏。请参阅Watusimoto关于该问题的帖子。我不确定这是否是因为一个损坏的元表,我在这里想问一些非常奇怪的行为 问题的表现形式 例如,我们创建一个对象并将其添加到如下级别: t = TextItem.new() t:setText("

背景

我和Watusimoto一起做游戏。我们使用一个LuaReAPPER的变体将我们的C++对象与游戏中的Lua对象连接起来。我们还使用一种称为Lua的变体来加速向量运算

一段时间以来,我们一直在努力解决一个我们无法解决的bug。将发生随机崩溃,这表明元表已损坏。请参阅Watusimoto关于该问题的帖子。我不确定这是否是因为一个损坏的元表,我在这里想问一些非常奇怪的行为

问题的表现形式

例如,我们创建一个对象并将其添加到如下级别:

t = TextItem.new()
t:setText("hello")
levelgen:addItem(t)
然而,游戏有时(并非总是)会崩溃。有一个错误:

attempt to call missing or unknown method 'addItem' (a nil value)
根据回答Watusimoto上述帖子时给出的建议,我将最后一行改为:

local ok, res = pcall(function() levelgen:addItem(t) end)

if not ok then
    local s = "Invalid levelgen value: "..tostring(levelgen).." "..type(levelgen).."\n"

    for k, v in pairs(getmetatable(levelgen)) do 
        s = s.."meta "..tostring(k).." "..tostring(v).."\n"
    end

    error(res..s)
end
如果从中调用方法时出错,则打印出
levelgen
的元表

然而,这是疯狂的,当它失败并打印出元表时,元表正是它应该的样子(使用正确的
addItem
调用和一切)。如果我在脚本加载时打印
levelgen
的元表,并且当它使用上面的
pcall
失败时,它们是相同的,指向userdata的每个调用和指针都是相同的

这就好像
levelgen
的元表在随机地自动消失

有人知道发生了什么事吗

多谢各位


注意:只有
levelgen
对象才会发生这种情况。例如,它也发生在上面提到的
TestItem
对象上。事实上,相同的代码在我的计算机上以
levelgen:addItem(t)
的行崩溃,但在另一个开发人员的计算机上以
t:setText(“hello”)
的行崩溃,并显示相同的错误消息
缺少或未知的方法“setText”(一个空值)

与任何谜团一样,您需要一层一层地将其剥离。我建议大家按照Lua所要做的步骤来做,并试着发现所走的道路偏离了你的期望:

getmetatable(levelgen)。\uu index
返回什么?如果它是一个表,则检查它的内容是否有
addItem
。如果它是一个函数,那么试着用
(表,“addItem”)
调用它,看看它返回什么

检查
getmetatable
是否在调用前后(或调用失败时)返回对同一对象的引用

调用所经历的元表间接寻址有几个级别吗?如果是这样,请尝试使用显式调用遵循相同的路径,并查看差异所在

如果没有其他引用,是否使用了可能导致值消失的

当您检测到它失败时,是否可以提供一个“默认”值,并继续查看它是否在以后再次“找到”此方法?或者当它坏了以后每次打电话都会坏

如果您为addItem保存一个适当的值,并在检测到它已损坏时“修复”它,该怎么办

如果您只是处理错误(就像您所做的那样)并调用它10次呢?它是否至少显示一次有效结果(失败后)?100次?如果在同一个方法工作时继续调用它,它会失败吗?这可能会帮助您找出一个更容易再现的错误


我不熟悉LuaWrapper,无法提供更具体的问题,但如果我是您,我会采取以下步骤。

我强烈怀疑问题在于您有一个类似于以下内容的类或结构:

struct Foo
{
    Bar bar;
    // Other fields follow
}
你通过LuaWrapper向Lua展示了Foo和Bar。这里重要的一点是,
bar
Foo
结构上的第一个字段。或者,您可能有一些继承自其他基类的类,并且派生类和基类都将公开给LuaWrapper

LuaWrapper使用一个称为标识符的函数来唯一地跟踪每个对象(比如给定对象是否已添加到Lua状态)。默认情况下,它使用对象地址作为键。在类似上面提出的情况下,Foo和Bar在内存中可能都有相同的地址,因此LuaWrapper可能会混淆

这可能导致在尝试查找方法时获取错误对象的元表。显然,由于它正在查看错误的元表,它将找不到您想要的方法,因此它将显示为您的元表神秘地丢失了条目


我签入了一个更改,它跟踪每种类型的每个对象的数据,而不是在一个巨大的堆中。如果您将您的副本LuaWrapper从存储库更新为最新版本,我可以相当肯定您的问题将得到解决

与上游(commit 3c54015)LuaWrapper合并后,此问题已消失。这似乎是LuaWrapper中的一个bug


谢谢亚历克斯

你试过在Valgrind下运行你的代码吗?您可能会有一个C++内存损坏问题。嗨,是的,我们已经通过ValGRN运行过好几次了,在修复了内存错误(在不相关的代码中)之后,问题仍然非常奇怪。您能够将问题简化为一个简短的测试用例吗?我上面展示的代码就是简短的测试用例。它在加载关卡时加载,并将随机崩溃(通常不是第一次加载关卡,而是在同一游戏会话中重新启动关卡后,第二次或第三次…有时直到第八次左右)我想如果不启动整个游戏引擎,你就无法实现这一独立功能?我认为你的诊断可能是正确的,但原因是错误的。类可能会变得混乱,但不是因为继承,而是因为我们正在快速地循环对象,C++可能在Lua的垃圾回收有机会清理之前为不同的对象类型重新分配地址。