Сбой приложения с объектами, созданными в цикле с использованием 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
кажется, делает всю работу.