2014-02-15 3 views
3

Как освободить память, выделенную lua_newuserdata?Как освободить память, выделенную lua_newuserdata, с помощью оператора delete?

У меня есть класс с именем Foo, и этот класс имеет конструктор и desstructor, и мне нужно выполнить оба, но я не знаю, как использовать C++ оператор delete, потому что я не использовал new выделить память ,

Я попытался сделать это в функции Lua новой, которое создает объект:

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

и в функции ого Я попробовал:

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

Но я получил ошибку сегментации.

+1

Lua автоматически освобождает память, если нет ссылок на пользовательские данные. Если вы хотите обнаружить, когда это произойдет, вы можете добавить метатет '__gc'. – immibis

ответ

8

В этом случае вам необходимо использовать концепцию lua под названием userdatum, это означает, что вам нужно выделить указатель на свой объект, используя lua_newuserdata.

Чтобы выделить память сделать что-то вроде этого:

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

и в функции сборщика мусора вы можете сделать это:

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

Ниже приведен полный пример кода с использованием концепции 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; 
} 
+0

Должно ли это быть «sizeof (Foo)»; или "sizeof (Foo *);"? –

+0

Нет, вы должны выделить достаточно памяти объекту Foo, а не только указателю, вам нужно знать реальный размер объекта Foo. – Alex

+1

Я верю в вас, я спросил его, потому что я использую библиотеку lua под названием «Eluna» и в ее исходном коде есть такой же код, как: UserData ** ud = static_cast **> (lua_newuserdata (L , sizeof (UserData *))); https://github.com/radiotail/eluna/blob/master/eluna/ELuna.h line 345 Эта библиотека, кажется, работает хорошо, поэтому я задаюсь вопросом, где я получил недоразумение. –

Смежные вопросы