3

I have a class that I use in my C++ code and in some Lua scripts. The relevant portion of the class looks like:

typedef boost::shared_ptr<Thing> ThingPtr; // convenient

class Thing
{
public:
    Thing() { /* do some stuff */ }
    ~virtual Thing() { }

    ThingPtr createThing()
    {
        ThingPtr thing(new Thing);

        // initialization can't be done in constructor
        thing->doSomeInit();

        return thing;
    }     

// other stuff....

};

I expose this class in Lua (without using binding or anything "fancy"). Before I added the factory function, my Lua function to create a Thing looked like:

int MyLua::newThing(lua_State* L)
{
    int size = sizeof(Thing);

    // allocate a new Thing object in place
    new ((Thing*)lua_newuserdata(L, size)) Thing();

    luaL_setmetatable(L, "MyStuff.thing");

    return 1;
}

Once I added the factory function I did something like:

int MyLua::newThing(lua_State* L)
{
    int size = sizeof(Thing);

    // allocate a new Thing object in place
    Thing* thing = new ((Thing*)lua_newuserdata(L, size)) Thing();
    thing->doSomeInit();

    luaL_setmetatable(L, "MyStuff.thing");

    return 1;
}

This is fine seemed fine except that now I want to make the constructor of Thing private in order to enforce the use of the factory function in other places in the C++ code. So, now I have something like:

int MyLua::newThing(lua_State* L)
{
    int size = sizeof(Thing);
    ThingPtr thing = Thing::createThing();

    void* space = lua_newuserdata(L, size);
    memcpy(space, client.get(), size);

    luaL_setmetatable(L, "MyStuff.thing");

    return 1;
}

My question is: is there a better way to do this? The call to memcpy makes me feel uncomfortable.

4

2 回答 2

1

您不能将 C++ 对象的所有权转移给 Lua。

您的原始代码有缺陷,因为它永远不会为您Thing的 s 调用析构函数。虽然 Lua 会对通过 分配的内存进行垃圾回收lua_newuserdata,但它不会调用对象的析构函数(因为 Lua 作为 C 库,不知道析构函数的概念)。

因此,您将需要在 C++ 端有一个单独的构造来管理对象的生命周期,并且只将原始(非拥有)指针传递给 Lua 以作为用户数据公开。

于 2013-10-02T10:45:04.643 回答
1

它应该让你不舒服;memcpy仅允许用于可简单复制的类型(Thing不是这样的类型)。我什至不确定这new (lua_newuserdata(L, size)) Thing()是允许的,因为默认情况下 Lua 使用realloc声明新内存,这可能导致内存被移动(即无论如何realloc可能)。memcpy

IMO 的解决方案是动态分配您的Thing(您的createThing工厂似乎确实这样做了,但使用智能指针)并使用__gc清理对象的元方法将指向用户数据中的对象的 C 指针存储在用户数据中。使用智能指针,这会更复杂,但它需要在堆上存储智能指针的副本,在用户数据中存储指向智能指针的 C 指针,然后在元方法中释放智能指针__gc

于 2013-10-02T10:32:53.923 回答