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

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

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

È stato utile?

Soluzione

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top