C ++& Lua Api,使用工厂功能进行分配

时间:2013-10-02 10:25:12

标签: c++ lua

我有一个我在C ++代码和一些Lua脚本中使用的类。该课程的相关部分如下:

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....

};

我在Lua中公开这个类(不使用绑定或任何“花哨”)。在我添加工厂函数之前,我创建 Thing 的Lua函数看起来像:

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;
}

一旦我添加了工厂功能,我做了类似的事情:

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;
}

这很好看,但现在我想将 Thing 的构造函数设为私有,以便在C ++代码的其他地方强制使用工厂函数。所以,现在我有类似的东西:

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;
}

我的问题是:有更好的方法吗?对 memcpy 的调用让我感到不舒服。

2 个答案:

答案 0 :(得分:1)

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

IMO的解决方案是动态分配你的Thing(看起来你的createThing工厂确实用智能指针做)并在用户数据中存储一个指向对象的C指针清除对象的__gc metamethod。使用智能指针这更复杂,但它涉及将智能指针的副本存储在堆上,将C指针存储到用户数据中的智能指针,然后释放__gc元方法中的智能指针。

答案 1 :(得分:1)

您无法将C ++对象的所有权转让给Lua。

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

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