繁体   English   中英

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

[英]Application crashes with objects created in loop using Luabind in C++

我正在尝试将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对象是从Node类继承的。

有谁知道会导致这种奇怪错误的原因吗? 我很乐意提供任何帮助。

您有严重的所有权问题。

在C / C ++中,一段代码“拥有”一个指针或其他资源(如果该代码或对象承担销毁它的责任)。 它保持它活着,而它需要它,它可以确保使用完被摧毁。

保持对谁拥有什么的理解,这对于任何甚至非常复杂的C或C ++程序都至关重要。

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

所以这:

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

将创建一个生命周期受Lua状态控制的Sprite对象。 当Lua状态不再具有对其的任何活动引用时,则Lua状态将可以自由删除它。

我不知道您的代码如何工作,但是这一行:

local o = CircleObject(s)

建议CircleObject的构造函数应该声明对其所给定对象的所有权(因此CircleObject决定何时删除它)。 如果是这样,那么在将此构造函数与Luabind绑定时,您需要实际声明。

如果不应该使用CircleObject的构造方法来拥有所有权,那么……坦率地说,您的设计CircleObject怀疑; 长期存储您不拥有的指针只是在乞求弄糟。 但是,如果确实要存储别人拥有的指针,则您需要使用Lua机制来确保Sprite只要CircleObject保持活动CircleObject

类似地, Node::AddChild函数看起来像在声明所给定节点的所有权。 可以这样进行:

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

_1表示函数的第一个参数。 这意味着Node要求拥有第一个参数的所有权; 如果它由Lua拥有,则此所有权链现在断开,并且C ++现在拥有该对象。

就个人而言,我会说此API对Lua不利。 您似乎希望所有次要对象所有权都可以用C ++代码完成。 因此,Lua应该调用C ++函数来设置所有这些次要对象,而不必干预Lua。 Lua应该调用NodeManager的成员函数以获取/创建Node ,然后应该调用将在该Node创建Sprite的函数。

Lua不必处理BoxObject类的细节。 它不必直接创建Sprite对象并将其放入Node

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM