【发布时间】:2015-07-14 20:41:30
【问题描述】:
我正在为我们的应用程序编写一个 lua (5.1) 扩展,允许我们的客户在没有我们支持的情况下使用更多屏幕对其进行扩展。
总的来说,这工作得很好,并且在十几个包装器的帮助下甚至非常舒适,但现在我遇到了以下情况:
我有两个用户数据对象,一个对象 Timer 和一个对象 Window。 用户可以通过简单地定义他们的成员 OnTimer 和 OnSizeChanged 来将事件“附加”到他们。
这仍然很有效: mainLoop (C++) -> 检查所有计时器 (C++)-> 附加的脚本对象? (C++),然后:
// get ud by reference / stack: +1 / 1
lua_rawgeti(mState, LUA_REGISTRYINDEX, miReferenceId);
lua_getfenv(mState, -1); // get attached table / +1 / 2 total
lua_getfield(mState, -1, functionName.ToChar()); // +1 / 3 total
if (!lua_isfunction(mState, -1))
{
...
}
lua_remove(mState, -2); // remove table / -1 / 2 total
lua_remove(mState, -2); // remove ud / -1 / 1 total, just function remaining
// ( .. user data still pushed at this point ..)
lua_pcall(mState, 1, 0, 0);
所以在以下场景中一切都很好(在开始调用之前和之后堆栈肯定是 0):
function OnTimer(Self)
Log("Some text") // Log calls C++ luaLog with 1 argument
end
myTimer = timer.new()
myTimer.OnTimer=OnTimer;
如果 lua 脚本看起来像这样:
timer = timer.new()
window = window.new()
function OnTimer(Self)
window:SetSize(323.5,234.5)
end
function OnSizeChanged(Self,NewWidth,NewHeight)
Log("Sized changed")
end
timer.OnTimer = OnTimer
window.OnSizeChanged = OnSizeChanged
那么C++中的调用栈将是:
timer::HandleTimer (C++) ->
push "OnTimer" function ->
push timer ud ->
pcall (L,1) -> .. (Lua)
static int luaChangeSize(lua_State *L) (back to C++) ->
Window::SetSize ->
The window sees "oooooooh, an event handler has been assigned" ->
push "OnSizeChanged" function, window ud, x, y ->
pcall(L,3,0,0) -> .. (Lua) ->
int luaLog(lua_state* L) (back to C++ again)
当然,在调用 OnSizeChanged 的时候,堆栈仍然包含之前的 luaChangeSize 回调的内容,并且不为空。
我认为我可以通过在调用 Window::SetSize 之前弹出 luaChangeSize 的所有参数并在之后恢复它们来简单地清理堆栈,但这不起作用。结果有点随机,具体取决于调用堆栈的星座,从“无法调用数字”到再次随机调用堆栈上的前一个函数。 (所有调用前后 gettop 绝对为 0)。
那么:我如何“备份”当前堆栈并在之后恢复它,因为 lua 在 C++ -> Lua -> C++ 星座中自己完成它?
非常感谢。
【问题讨论】:
标签: c++ recursion lua backup callstack