I'm exposing the internals of my application to Lua, via luabind, where in C++ I have a Container
of shared_ptr<Item>
where Item
is an abstract base class. Derived classes include ItemA
and ItemB
.
To expose these to luabind, I use a couple of wrapper classes (since I want the Container to have a different editing mechanism in the script interface). I want to be able to enumerate the Items in a Container in a Lua script like this:
container=app.container
for i,event in ipairs(container.items) do
print(tostring(event))
end
The problems I have are that I can expose this functionality by returning raw pointers to ItemWrappers
, but this leads to memory leaks as the ItemWrapper
destructors are never called. If I try to declare the wrappers in the luabind as smart pointers as described in the docs then this throws a 'Trying to use unregistered class' exception when I try to return a smart pointer as a lua object.
The wrappers are defined like this:
class ContainerWrapper {
public:
ContainerWrapper(Container& c) : container(c) {};
Container& c; // reference to the actual container
};
class ItemWrapper {
public:
virtual ~ItemWrapper() {};
ItemWrapper(int itemIndex_) : itemIndex(itemIndex_) {};
int itemIndex; // items are addressed by index
};
class ItemAWrapper : public ItemWrapper {
public:
ItemAWrapper(int itemIndex_) : ItemWrapper(itemIndex_) {};
};
The luabind registration looks like this: (if I don't use smart pointers)
class_<ItemWrapper>("Item") ,
class_<ItemAWrapper, ItemWrapper>("ItemA")
and like this if I do:
class_<ItemWrapper, std::tr1::shared_ptr<ItemWrapper> >("Item") ,
class_<ItemAWrapper, ItemWrapper, std::tr1::shared_ptr<ItemWrapper> >("ItemA")
The function to expose the items
member of Container
returns a lua table:
luabind::object Container::getItemsAsTable(lua_State* L)
{
luabind::object table=luabind::newtable(L);
for (int i=0; i<items.size(); i++) {
table[i+1]= new ItemAWrapper(); // or function to return pointer/smart pointer
}
return table;
}
Is this the correct way of setting the value in the table? It's the assignment that generates the exception if I pass a smart pointer, but if I pass a raw pointer then it doesn't seem to assign it into a smart pointer internally and the object gets leaked. Doing garbage collection doesn't help either.
Lua is already polymorphic. So your getItemsAsTable
function doesn't need to new
these ItemWrapper
objects. Just stick values in it. Like this: table[i+1] = ItemAWrapper()
. Unless there's something going on where you need to use a pointer (like if changing the Lua table should be reflected in C++), don't bother. Just use a value.