应用程序在C ++中使用Luabind在循环中创建的对象崩溃

时间:2012-08-04 15:07:00

标签: c++ lua luabind

我正在尝试将Lua用于我的游戏引擎原型,但我遇到了奇怪的错误。

我的目标是使用Lua在循环中创建X对象并渲染它们。

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

如果我这样做,代码可以正常运行,但游戏会在瞬间到几秒的随机时间内崩溃。如果我只使用在循环中创建的对象,而不是手动创建的对象,则游戏会立即崩溃。

但是,如果我在C ++中编写等效的Lua代码,它运行没有任何问题。

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

除AddChild

外,每个方法都接受并返回void
virtual void AddChild(Node *child);

Sprite和Box aand Circle Objects继承自Node类。

有没有人知道什么会导致这个奇怪的错误?我会很高兴得到任何帮助。

1 个答案:

答案 0 :(得分:1)

您有严重的所有权问题。

在C / C ++中,如果该代码或对象承担销毁它的责任,则一段代码“拥有”指针或其他资源。它在需要时保持活着,并确保在 it 使用它时它被销毁。

了解谁拥有对于任何复杂的C或C ++程序至关重要的内容。

当Luabind从Lua 创建C ++对象时,Lua脚本拥有该对象。这意味着Lua的垃圾收集器将决定何时删除它。

所以这个:

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

将创建一个Sprite对象,其生命周期由Lua状态控制。当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不必干涉。 Lua应该调用NodeManager的成员函数来获取/创建Node,然后它应该调用一个在Sprite内创建Node的函数。 / p>

Lua不应该处理BoxObject这样的细枝末节。它不应该直接创建Sprite对象并将其放入Node

此外,个人而言,此API也不适合 C ++ 。如果Sprite需要存储在某种容器中,并且该容器需要存储在某种Node中,那么就不可能创建Sprite 没有将其存储在容器中。这就是工厂的功能。我甚至不确定BoxObjectCircleObject的用途,因为Sprite似乎正在完成所有工作。