如何释放由lua_newuserdata与delete操作符分配的内存?

时间:2020-12-29 21:17:26

How can I free memory allocated by lua_newuserdata?

如何释放由lua_newuserdata分配的内存?

I have a class called Foo, and this class has a constructor and desstructor, and I need execute both, but I don't know how to use the C++ operator delete, because I didn't use new to allocate memory.

我有一个叫Foo的类,这个类有一个构造函数和desstructor,我需要同时执行这两个,但是我不知道如何使用c++运算符delete,因为我没有使用new来分配内存。

I tried do that in the Lua function new that create the object:

我在创建对象的Lua新函数中尝试过:

Foo *pf = reinterpret_cast<Foo *>(
                lua_newuserdata(L, sizeof(Foo)));

and at gc function I tried that:

在gc函数中,我试过

Foo *foo = reinterpret_cast<Foo *>(lua_touserdata(L, 1));
delete foo;

But I got a segmentation fault.

但是我有分割错误。

1 个解决方案

#1


8  

In this case you need to use a lua concept called userdatum, it means, you need to allocate a pointer to your object using lua_newuserdata.

在这种情况下,您需要使用一个名为userdatum的lua概念,这意味着您需要使用lua_newuserdata为对象分配一个指针。

To allocate memory do something like that:

为了分配内存,做一些类似的事情:

Foo **pfoo = reinterpret_cast<Foo **>(lua_newuserdata(L, sizeof(Foo*)));
*pfoo = new Foo(foo);

and at the garbage collector function you can do that:

在垃圾收集器函数中你可以这样做:

Foo **foo = reinterpret_cast<Foo **>(lua_touserdata(L, 1));
delete *foo;

Below is a complete code example using the concept of userdatum

下面是一个使用userdatum概念的完整代码示例。

#define FOO     "foo"

class Foo {
public:
  Foo(const char *name) {
    this->name = (char *) malloc(strlen(name) + 1);
    strncpy(this->name, name, strlen(name));
  }

  Foo(const Foo &obj) {
    this->name = (char *) malloc(strlen(name) + 1);
    strncpy(this->name, obj.name, strlen(obj.name));
  }

  const char* get_name() const {
    return this->name;
  }

  ~Foo() {
    free(this->name);
  }
private:
  char *name;
};

static Foo* push_foo(lua_State *L, Foo foo) {

  Foo **pfoo = reinterpret_cast<Foo **>(
                lua_newuserdata(L, sizeof(Foo*)));
  *pfoo = new Foo(foo);

  luaL_getmetatable(L, FOO);
  lua_setmetatable(L, -2);

  return *pfoo;
}

static Foo* chk_foo(lua_State *L, int index) {
  Foo *foo;
  luaL_checktype(L, index, LUA_TUSERDATA);
  foo = *reinterpret_cast<Foo **>(luaL_checkudata(L, index, FOO));
  if (foo == NULL)
    luaL_error(L, "error");

  return foo;
}

static int foo_new(lua_State *L) {
  int argc = lua_gettop(L);

  if(argc != 1)
    luaL_error(L, "string argument expected");

  const char* str = luaL_checkstring(L, 1);

  push_foo(L, Foo(str));

  luaL_getmetatable(L, FOO);
  lua_setmetatable(L, -2);
  std::cout << "Lua object created!" << std::endl;
  return 1;
}

static int foo_get(lua_State *L) {
  Foo *foo = chk_foo(L, 1);
  luaL_argcheck(L, foo != NULL, 1, "Error foo");

  lua_pushstring(L, foo->get_name());
  return 1;
}

static int foo_gc(lua_State *L) {
  Foo **foo = reinterpret_cast<Foo **>(lua_touserdata(L, 1));
  luaL_argcheck(L, *foo != NULL, 1, "Error foo");
  delete *foo;
  std::cout << "Lua GC executed!" << std::endl;
  return 0;
}

int luaopen_foolib(lua_State *L) {
  static const luaL_Reg Obj_lib[] = {
    { "get", &foo_get },
    { NULL, NULL }
  };

  static const luaL_Reg LuaLib_Foo[] = {
    { "new", &foo_new },
    { NULL, NULL }
  };

  luaL_newlib(L, LuaLib_Foo);

  // Stack: MyLib
  luaL_newmetatable(L, FOO);
  luaL_newlib(L, Obj_lib);
  lua_setfield(L, -2, "__index");

  lua_pushstring(L, "__gc");
  lua_pushcfunction(L, foo_gc);
  lua_settable(L, -3);
  lua_pop(L, 1);

  return 1;
}

int main(int argc, char **argv) {
  lua_State *L;
  L = luaL_newstate();

  luaL_openlibs(L);

  luaL_requiref(L, "foo", &luaopen_foolib, 1);
  lua_pop(L, 1);

  const char *code = "f = foo.new(\"my_test\")\nprint(f:get())";

  if(luaL_loadstring(L, code) != 0)
  {
    std::cout << "Could not load: " << argv[1] << std::endl;
    exit(EXIT_FAILURE);
  }

  if(lua_pcall(L, 0, 0, 0) != 0)
  {
    std::cout << "Error: " << lua_tostring(L, -1) << std::endl;
    lua_pop(L, 1);
    exit(EXIT_FAILURE);
  }
  lua_close(L);
  return 0;
}

#1


8  

In this case you need to use a lua concept called userdatum, it means, you need to allocate a pointer to your object using lua_newuserdata.

在这种情况下,您需要使用一个名为userdatum的lua概念,这意味着您需要使用lua_newuserdata为对象分配一个指针。

To allocate memory do something like that:

为了分配内存,做一些类似的事情:

Foo **pfoo = reinterpret_cast<Foo **>(lua_newuserdata(L, sizeof(Foo*)));
*pfoo = new Foo(foo);

and at the garbage collector function you can do that:

在垃圾收集器函数中你可以这样做:

Foo **foo = reinterpret_cast<Foo **>(lua_touserdata(L, 1));
delete *foo;

Below is a complete code example using the concept of userdatum

下面是一个使用userdatum概念的完整代码示例。

#define FOO     "foo"

class Foo {
public:
  Foo(const char *name) {
    this->name = (char *) malloc(strlen(name) + 1);
    strncpy(this->name, name, strlen(name));
  }

  Foo(const Foo &obj) {
    this->name = (char *) malloc(strlen(name) + 1);
    strncpy(this->name, obj.name, strlen(obj.name));
  }

  const char* get_name() const {
    return this->name;
  }

  ~Foo() {
    free(this->name);
  }
private:
  char *name;
};

static Foo* push_foo(lua_State *L, Foo foo) {

  Foo **pfoo = reinterpret_cast<Foo **>(
                lua_newuserdata(L, sizeof(Foo*)));
  *pfoo = new Foo(foo);

  luaL_getmetatable(L, FOO);
  lua_setmetatable(L, -2);

  return *pfoo;
}

static Foo* chk_foo(lua_State *L, int index) {
  Foo *foo;
  luaL_checktype(L, index, LUA_TUSERDATA);
  foo = *reinterpret_cast<Foo **>(luaL_checkudata(L, index, FOO));
  if (foo == NULL)
    luaL_error(L, "error");

  return foo;
}

static int foo_new(lua_State *L) {
  int argc = lua_gettop(L);

  if(argc != 1)
    luaL_error(L, "string argument expected");

  const char* str = luaL_checkstring(L, 1);

  push_foo(L, Foo(str));

  luaL_getmetatable(L, FOO);
  lua_setmetatable(L, -2);
  std::cout << "Lua object created!" << std::endl;
  return 1;
}

static int foo_get(lua_State *L) {
  Foo *foo = chk_foo(L, 1);
  luaL_argcheck(L, foo != NULL, 1, "Error foo");

  lua_pushstring(L, foo->get_name());
  return 1;
}

static int foo_gc(lua_State *L) {
  Foo **foo = reinterpret_cast<Foo **>(lua_touserdata(L, 1));
  luaL_argcheck(L, *foo != NULL, 1, "Error foo");
  delete *foo;
  std::cout << "Lua GC executed!" << std::endl;
  return 0;
}

int luaopen_foolib(lua_State *L) {
  static const luaL_Reg Obj_lib[] = {
    { "get", &foo_get },
    { NULL, NULL }
  };

  static const luaL_Reg LuaLib_Foo[] = {
    { "new", &foo_new },
    { NULL, NULL }
  };

  luaL_newlib(L, LuaLib_Foo);

  // Stack: MyLib
  luaL_newmetatable(L, FOO);
  luaL_newlib(L, Obj_lib);
  lua_setfield(L, -2, "__index");

  lua_pushstring(L, "__gc");
  lua_pushcfunction(L, foo_gc);
  lua_settable(L, -3);
  lua_pop(L, 1);

  return 1;
}

int main(int argc, char **argv) {
  lua_State *L;
  L = luaL_newstate();

  luaL_openlibs(L);

  luaL_requiref(L, "foo", &luaopen_foolib, 1);
  lua_pop(L, 1);

  const char *code = "f = foo.new(\"my_test\")\nprint(f:get())";

  if(luaL_loadstring(L, code) != 0)
  {
    std::cout << "Could not load: " << argv[1] << std::endl;
    exit(EXIT_FAILURE);
  }

  if(lua_pcall(L, 0, 0, 0) != 0)
  {
    std::cout << "Error: " << lua_tostring(L, -1) << std::endl;
    lua_pop(L, 1);
    exit(EXIT_FAILURE);
  }
  lua_close(L);
  return 0;
}