Правильный способ освободить массив указателей во входной карте типов SWIG? - PullRequest
0 голосов
/ 05 июня 2018

Привет. Я пытаюсь обернуть следующую функцию с помощью SWIG.

static void readTable(int argc, t_atom *argv) { //accepts table in Lua e.g. readTable({"ab",3});

        for (int i=0; i<argc; ++i) {

            if (argv[i].a_type == A_FLOAT)
                printf("FLOAT : %g\n", argv[i].a_w.w_float);
            else if (argv[i].a_type == A_SYMBOL)
                printf("SYMBOL : %s\n", argv[i].a_w.w_symbol->s_name);
        }
    }

Вот созданная мной карта типов.

%include "exception.i"
%typemap(in) (int argc, t_atom *argv)
{
    if (!lua_istable(L, 1)) {
      SWIG_exception(SWIG_RuntimeError, "argument mismatch: table expected");
    }
    lua_len(L, 1);
    $1 = lua_tointeger(L, -1);
    $2 = (t_atom *)getbytes($1 * sizeof(t_atom)); //internally calls calloc()

    for (int i=0; i<$1; ++i) {

        lua_pushinteger(L, i+1);
        lua_gettable(L, 1);

        if(lua_isnumber(L, -1)) {

            $2[i].a_type = A_FLOAT;
            $2[i].a_w.w_float = lua_tonumber(L, -1);
        }          
        else if(lua_isstring(L, -1)) {

            $2[i].a_type = A_SYMBOL;
            $2[i].a_w.w_symbol = gensym(lua_tostring(L, -1));
        }
    }
    freebytes($2, $1 * sizeof(t_atom)); //internally calls free()
}

Как видите, я выделяю память длямассив, использующий getbytes(), который внутренне вызывает calloc() и освобождающий память, используя freebytes(), который внутренне вызывает free().

Удивительно, но когда я вызываю readTable() функцию в Lua, она работает без сбоев.

например, вызов test.readTable({3, "abc"}) в Lua выводит следующий результат.

FLOAT : 3
SYMBOL : abc

Мои вопросы

a) Как readTable() печатать результаты без сбоев, когдаЯ освободил память в интерфейсе SWIG?Может быть, память не освобождается должным образом?

b) Если а) не имеет смысла или небезопасно для использования, вы бы порекомендовали вместо этого вызывать freebytes() внутри функции readTable(), чтобы ее можно былокак следующее?

static void readTable(int argc, t_atom *argv) {

        for (int i=0; i<argc; ++i) {

            if (argv[i].a_type == A_FLOAT)
                post("FLOAT : %g", argv[i].a_w.w_float);
            else if (argv[i].a_type == A_SYMBOL)
                post("SYMBOL : %s", argv[i].a_w.w_symbol->s_name);
        }
        freebytes(argv, argc * sizeof(t_atom));
    }

1 Ответ

0 голосов
/ 06 июня 2018

Это именно та ситуация, для которой %typemap(freearg).

%include "exception.i"

%typemap(in) (int argc, t_atom *argv) {
    if (!lua_istable(L, $input)) {
        SWIG_exception(SWIG_RuntimeError, "argument mismatch: table expected");
    }
    lua_len(L, $input);
    $1 = lua_tointeger(L, -1);
    $2 = (t_atom *)getbytes($1 * sizeof(t_atom)); // internally calls calloc()

    for (int i = 0; i < $1; ++i) {

        lua_pushinteger(L, i + 1);
        lua_gettable(L, $input);

        if (lua_isnumber(L, -1)) {
            $2[i].a_type = A_FLOAT;
            $2[i].a_w.w_float = lua_tonumber(L, -1);
        } else if (lua_isstring(L, -1)) {
            $2[i].a_type = A_SYMBOL;
            $2[i].a_w.w_symbol = gensym(lua_tostring(L, -1));
        } else {
            SWIG_exception(SWIG_RuntimeError, "unhandled argument type");
        }
    }
}

%typemap(freearg) (int argc, t_atom *argv) {
    freebytes($2, $1 * sizeof(t_atom)); // internally calls free()
}

static void readTable(const std::string &name, int argc, t_atom *argv);

Это сгенерированный код из SWIG 3.0

static int _wrap_readTable(lua_State* L) {
  int SWIG_arg = 0;
  std::string *arg1 = 0 ;
  int arg2 ;
  t_atom *arg3 = (t_atom *) 0 ;

  SWIG_check_num_args("readTable",2,2)
  if(!lua_isuserdata(L,1)) SWIG_fail_arg("readTable",1,"std::string const &");

  if (!SWIG_IsOK(SWIG_ConvertPtr(L,1,(void**)&arg1,SWIGTYPE_p_std__string,0))){
    SWIG_fail_ptr("readTable",1,SWIGTYPE_p_std__string);
  }

  {
    if (!lua_istable(L, 2)) {
      SWIG_exception(SWIG_RuntimeError, "argument mismatch: table expected");
    }
    lua_len(L, 2);
    arg2 = lua_tointeger(L, -1);
    arg3 = (t_atom *)getbytes(arg2 * sizeof(t_atom)); // internally calls calloc()

    for (int i = 0; i < arg2; ++i) {
      lua_pushinteger(L, i + 1);
      lua_gettable(L, 2);

      if (lua_isnumber(L, -1)) {
        arg3[i].a_type = A_FLOAT;
        arg3[i].a_w.w_float = lua_tonumber(L, -1);
      } else if (lua_isstring(L, -1)) {
        arg3[i].a_type = A_SYMBOL;
        arg3[i].a_w.w_symbol = gensym(lua_tostring(L, -1));
      } else {
        SWIG_exception(SWIG_RuntimeError, "unhandled argument type");
      }
    }
  }
  readTable((std::string const &)*arg1,arg2,arg3);

  {
    freebytes(arg3, arg2 * sizeof(t_atom)); // internally calls free()
  }
  return SWIG_arg;

  if(0) SWIG_fail;

fail:
  {
    freebytes(arg3, arg2 * sizeof(t_atom)); // internally calls free()
  }
  lua_error(L);
  return SWIG_arg;
}
...