lua若干问题

  • 映射式表不支持ipairs枚举。
  • 以初始化{}创建表时,不支持用变量表示的key值。
  • 枚举表时,pairs枚举的是随机次序。ipairs保证有序,但适用于数组(列表),不能用于映射表。
  • 对映射式表,以数字0作为key时,虽然insert时是第一个,但往往不会放在第一条,导致pairs枚举时,极容易出来乱序。当然,如果要保证排序,就该避免用映射表。

 

一、残留__metatable表

图1 错误使用了残留元表,方法指向无效函数,导致异常

在图1,cpp_query_goods_是aplt_leagor_khome表中字段,类型user_data。给它设了个元表,名称“cpp.vquery_goods”,元表有三个方法:__gc、__index和reload。如果运行正常,元表中方法的[function]应该会显示对应的C代码实现函数,见图2。

图2 正确元表,方法指向有效函数

那为什么会出现图1中[function]是空?

  1. 已存在个aplt_leagor_khome表,它有cpp_query_goods_字段,并设了元表cpp.vquery_goods,并有__gc等三个方法,此时[function]都指向有效C代码实现函数。
  2. 销毁aplt_leagor_khome表,即aplt_leagor_khome置nil。
  3. 垃圾回收:lua_gc(L, LUA_GCCOLLECT);
  4. 立即再次新建aplt_leagor_khome,再次增加cpp_query_goods_字段,只是增加,没给重新设元表,于是有可能会出现图1情况。不过更多时候是出现有这个表,而且__gc三个方法指向之前的有效C函数。

一旦出现图1情况,如果lua有类似以下代码。

cpp_query_goods是个类型user_data的变量。
cpp_query_goods_:reload();

由于reload指向一个无效C函数(图1调试窗口显示为空),cpp_query_goods_:reload将抛出图1所示异常。

第二次增加cpp_query_goods_字段,就没增加“cpp.vquery_goods”元表,可它的确存在了。不清楚这里面怎么个细节,猜测和lua的垃圾回收机制有关。

要避免列留元表造成的潜在干扰,一是在垃圾回收cpp_query_goods_时,加上手动释放元表,这样一来,第二次创建时,这元表应该肯定没了。目前rose没用这方法,代替要增加cpp_query_goods_字段时,不判断元表是不是存在,批正都重要设置元表。这也就保证了,一旦出现列留表,会把表中结应的C函数设到正确值。看下面代代码。

void luaW_pushvquery_goods(lua_State* L, tquery_goods& widget)
{
    tquery_goods** v = (tquery_goods**)lua_newuserdata(L, sizeof(tquery_goods*));
    *v = &widget;

    luaL_newmetatable(L, "cpp.vquery_goods");
    ....设置元表

不要使用以下逻辑。

    if (luaL_newmetatable(L, "cpp.vquery_goods")) {
        ....设置元表
    }

   当存在残留元表时,luaL_newmetatable会返回false,设置元表操作不执行了,有可能造成列留元表错,造成类似图1异常。

}

luaL_newmetatable会确保有一个名称是"cpp.vquery_goods"元表,并把该元表入栈。如果已经有此元表,luaL_newmetatable只是入栈,然后返回false。如果没有,新建一个,返回true。

全部评论: 0

    写评论: