Я открываю внутреннее устройство своего приложения Lua через luabind, где в C ++ у меня есть Container из shared_ptr<Item>, где Item - абстрактный базовый класс. Производные классы включают ItemA и ItemB.

Чтобы предоставить их luabind, я использую пару классов-оболочек (так как я хочу, чтобы у Контейнера был другой механизм редактирования в интерфейсе скрипта). Я хочу иметь возможность перечислять элементы в контейнере в сценарии Lua следующим образом:

container=app.container
for i,event in ipairs(container.items) do 
  print(tostring(event))
end

У меня проблемы в том, что я могу раскрыть эту функциональность, возвращая необработанные указатели на ItemWrappers, но это приводит к утечкам памяти, поскольку деструкторы ItemWrapper никогда не вызываются. Если я попытаюсь объявить обертки в luabind как интеллектуальные указатели , как описано в docs , то это вызывает исключение «Попытка использовать незарегистрированный класс» , когда я пытаюсь вернуть умный указатель как объект lua.

Обертки определяются следующим образом:

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_) {};
};

Регистрация luabind выглядит так: (если я не использую умные указатели)

class_<ItemWrapper>("Item") ,
class_<ItemAWrapper, ItemWrapper>("ItemA")

И вот так, если я это сделаю:

class_<ItemWrapper, std::tr1::shared_ptr<ItemWrapper> >("Item") ,
class_<ItemAWrapper, ItemWrapper, std::tr1::shared_ptr<ItemWrapper> >("ItemA")

Функция, открывающая член items в Container, возвращает таблицу lua:

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;
 }

Это правильный способ установки значения в таблице? Это назначение, которое генерирует исключение, если я передаю интеллектуальный указатель, но если я передаю необработанный указатель, он, похоже, не назначает его интеллектуальному указателю внутри, и объект утекает. Сборка мусора тоже не помогает.

1
the_mandrill 20 Мар 2013 в 18:07

1 ответ

Лучший ответ

Lua уже полиморфен. Таким образом, вашей функции getItemsAsTable не нужно new эти ItemWrapper объекты. Просто придерживайтесь ценностей. Как это: table[i+1] = ItemAWrapper(). Если что-то не происходит там, где вам нужно использовать указатель (например, если изменение таблицы Lua должно быть отражено в C ++), не беспокойтесь. Просто используйте значение.

1
Nicol Bolas 20 Мар 2013 в 18:28
Нет ли опасности порезаться?
 – 
the_mandrill
20 Мар 2013 в 18:59
Если вы вернете фактический тип, вы ничего не нарежете. Если это какой-то производный тип, который не предоставляется Lua, я бы сказал, что вы должны предоставить этот тип Lua.
 – 
Nicol Bolas
20 Мар 2013 в 19:01
Как вы можете вернуть зарегистрированный luabind тип по значению как luabind::object?
 – 
the_mandrill
20 Мар 2013 в 19:51
Ага: luabind::object(L, ItemWrapper())
 – 
the_mandrill
20 Мар 2013 в 20:41