How can I free memory allocated by 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.
I tried do that in the Lua function new that create the object:
Foo *pf = reinterpret_cast<Foo *>(
lua_newuserdata(L, sizeof(Foo)));
and at gc function I tried that:
Foo *foo = reinterpret_cast<Foo *>(lua_touserdata(L, 1));
delete foo;
But I got a segmentation fault.
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.
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
#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;
}