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.
Problems with leaks or 'unregistered class' when returning pointers to derived objects in luabind
-
24-03-2022 - |
Domanda
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.
Soluzione