我有一个我在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 的调用让我感到不舒服。
答案 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,以作为用户数据公开。