Problems with leaks or 'unregistered class' when returning pointers to derived objects in luabind

StackOverflow https://stackoverflow.com/questions/15525861

  •  24-03-2022
  •  | 
  •  

Pregunta

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.

¿Fue útil?

Solución

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top