Сбой приложения с объектами, созданными в цикле с использованием Luabind в C++

Я пытаюсь использовать Lua с моим прототипом игрового движка, но застрял с странной ошибкой.

Моя цель - создать X объектов в цикле с Lua и визуализировать их.

sprite = Sprite("icon.jpg", 300, 300, 0)
sprite2 = Sprite("icon.jpg", 100, 100, 0)

b1 = BoxObject(sprite)
b2 = BoxObject(sprite2)

sprite3 = Sprite("circle.png", 200, 100, 0)
sprite4 = Sprite("circle.png", 300, 100, 0)

b3 = CircleObject(sprite3)
b4 = CircleObject(sprite4)

n = Node()
n:AddChild(b1)
n:AddChild(b2)
n:AddChild(b3)
n:AddChild(b4)

for i = 0, 10, 1 do 
    x = math.random(700)
    y = math.random(500)
    n:AddChild(BoxObject(Sprite("icon.jpg", x, y, 0)))
end

for i = 0, 10, 1 do 
    x = math.random(700)
    y = math.random(500)
    local s = Sprite("circle.png", x, y, 0)
    local o = CircleObject(s)
    n:AddChild(BoxObject)
end

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

Однако, если я напишу эквивалентный код Lua на C++, он запустится без проблем.

for(int i = 0; i < 20; i++){
    float x = rand() % 700;
    float y = rand() % 500;

    n->AddChild(new BoxObject(new Sprite("icon.jpg", x, y)));
}

for(int i = 0; i < 20; i++){
    float x = rand() % 700;
    float y = rand() % 500;

    n->AddChild(new CircleObject(new Sprite("circle.png", x, y)));
}

Это мой Lua обязательный

static void Lua(lua_State *lua){
    luabind::module(lua)
    [
     luabind::class_<Node>("Node")
     .def(luabind::constructor<>())
     .def(luabind::constructor<float, float, float>())
     .def("Render", &Node::Render)
     .def("Move", &Node::Move)
     .def("Rotate", &Node::Rotate)
     .def("AddChild", &Node::AddChild)
     .def("RotateAroundPoint", &Node::RotateAroundPoint)
     ];
}

Каждый метод принимает и возвращает void, кроме AddChild

virtual void AddChild(Node *child);

Объекты Sprite и Box aand Circle наследуются от класса Node.

У кого-нибудь есть идея, что может вызвать эту странную ошибку? Буду рад любой помощи.

1 ответ

У вас серьезные проблемы с владением.

В C/C++ фрагмент кода "владеет" указателем или другим ресурсом, если этот код или объект берет на себя ответственность за его уничтожение. Он сохраняет его живым, пока он в нем нуждается, и гарантирует, что он будет уничтожен, когда он будет закончен, используя его.

Поддержание понимания того, кому принадлежит то, что жизненно важно для любой даже слегка сложной программы на C или C++.

Когда Luabind создает объект C++ из Lua, сценарию Lua принадлежит этот объект. Это означает, что сборщик мусора Lua решит, когда его удалить.

Итак, это:

local s = Sprite("circle.png", x, y, 0)

Создам Sprite Объект, чья жизнь управляется государством Луа. Когда состояние Lua больше не имеет активных ссылок на него, то состояние Lua будет свободно удалять его.

Я не знаю, как работает ваш код, но эта строка:

local o = CircleObject(s)

Предполагает, что CircleObjectПредполагается, что конструктор должен претендовать на владение объектом, который ему дан (таким образом, CircleObject решает, когда его удалить). Если это правда, то вам нужно указать это, когда вы связываете этот конструктор с Luabind.

Если CircleObjectконструктор не должен вступать во владение, тогда... ну, честно говоря, ваш дизайн подозрительный; долгосрочное хранение указателя, которым вы не владеете, просто просит чего-то напортачить. Но если он действительно должен хранить указатель, принадлежащий кому-то другому, то вам нужно использовать механизмы Lua, чтобы гарантировать, что Sprite остается в живых до тех пор, пока CircleObject делает.

Точно так же Node::AddChild функция выглядит так, как будто она претендует на владение тем узлом, который ей дан. Это будет сделано так:

.def("AddChild", &Node::AddChild, adopt(_1))

_1 означает первый параметр функции. Это означает, что Node претендует на владение первым параметром; если он принадлежит Lua, эта цепочка владения разорвана, и C++ теперь владеет объектом.

Лично я бы сказал, что этот API... не подходит для Lua. Похоже, вы хотите, чтобы все владения второстепенными объектами выполнялись в коде C++. Поэтому Lua должен вызывать функции C++, которые устанавливают все эти второстепенные объекты без вмешательства Lua. Луа должен вызвать функцию-член NodeManager чтобы получить / создать Nodeзатем он должен вызвать функцию, которая создаст Sprite в этом Node,

Луа не должен иметь дело с мелочами BoxObject и тому подобное. Это не должно напрямую создавать Sprite возразить и положить его в Node,

Кроме того, опять же, лично этот API также не подходит для C++. Если Sprite должен храниться в каком-то контейнере, и этот контейнер должен храниться в каком-то виде Nodeто не должно быть возможности создать Sprite без хранения его в контейнере. Это то, для чего предназначены фабричные функции. Я даже не уверен, что BoxObject а также CircleObject для, так как Sprite кажется, делает всю работу.

Другие вопросы по тегам