【问题标题】:Child objects are (seemingly) randomly set to NULL or an 'illegal object'; how to debug that?子对象(看似)随机设置为 NULL 或“非法对象”;如何调试?
【发布时间】:2013-04-28 19:39:54
【问题描述】:

我将 Cocos2d-x 用于我从 Cocos2d-iphone 移植的游戏。最初的程序员似乎使用了 Objective-C 的“特性”来避免在调用 nil 对象时崩溃,以此来做很多草率的事情。

如果这与我不知道的有关,但是,在我的代码中,我从不手动调用 release(),当然也不会删除或类似的东西。我什至根本不调用 ->removeObject() (尽管这不会导致与我相同的问题)。

现在的问题是:当游戏运行时,在随机时刻(它们不会是随机的,但现在显然是这样)子节点被设置为 NULL。这不仅会影响我的代码,还会影响 Cocos2d 内部。示例:

    CCLog("----------------");
    for(int j = 0; j < this->getChildren()->count(); j++)
    {
        CCObject *child = this->getChildren()->objectAtIndex(j);
        EnemySprite *enemy = dynamic_cast<EnemySprite*>(child);
        if (enemy != NULL) {
            CCLog("Enemy with tag %d found", enemy->getTag());
        }
    }
    EnemySprite *enemy = dynamic_cast<EnemySprite*>(this->getChildByTag(i));
    if (enemy == NULL) {

        CCLog("Now enemy with %d is NULL :(", i);
    }

在 getChildren() 看,所有带有标签的敌人都在那里并打印出来;

  • 找到标签为 1000 的敌人
  • 找到标签为 1001 的敌人
  • 找到标签为 1002 的敌人

在游戏过程中它会经常显示这个,直到显示这个;

  • 找到标签为 1000 的敌人
  • 找到标签为 1001 的敌人
  • 找到标签为 1002 的敌人
  • 现在 1001 的敌人是 NULL :(

然后崩溃。

在我看来,上面的代码应该是不可能的,因为我刚刚检查、验证和打印了那个对象......

但更有趣的是(也许只对我来说,也许是一些愚蠢的错误),这个

 this->getChildByTag(i)

内部也会随机出错;遍历孩子,它会找到一个 NULL 并在 Cocos2d 内部代码上得出结论:

        if(pNode && pNode->m_nTag == aTag)
            return pNode;

然后 pNode 不为 NULL(这就是断言不触发的原因),但看起来像这样:

http://o7.no/137JXC4(截图)

在这个项目中,cocos2d::CCCopying 对我来说已经是噩梦了;每次我看到它,我都知道有问题,但我不知道如何找到它。

我已经在 release() 删除行添加了一个断点;它没有被调用。就像我说的,我不会手动做任何类似的事情。

我使用 Xcode / iOS 进行调试,但在 Android 上的行为是相同的(但在我的计算机上,Eclipse 比 Xcode 慢,尤其是在调试期间)。

但是,我知道很难给我一个解决方案/原因;如果有人能告诉我如何解决这个问题,我会非常高兴。它在整个(相当大的)代码库中随机发生,我不知道如何找到这个问题......

希望有人能帮忙!

【问题讨论】:

  • 这似乎表示未定义的行为。一个可能的原因可能是您存储了一个指向局部变量的指针。
  • 这与在 Objective C 中的工作方式有显着不同吗?例如,如果我有一个方法 initEnemy() { EnemySprite *enemy = EnemySprite::create("enemy.png"); this->addChild(enemy, 5, 1000);因为我就是这样做的,而且 Cocos2dx 手册就是这样做的。
  • 另请注意,在循环之后,i 将等于 getChildren()-&gt;count(),因此在您的 getChildByTag 调用中,i 将超出范围。
  • 当错误发生时,它会按字面意思打印“正确的”i,并且我在所有问题之后添加了该代码作为调试。但你是对的,它还不清楚;我现在把它改成了 j。
  • 您是否忘记保留自动释放的内容?

标签: c++ xcode cocos2d-x


【解决方案1】:

有时 dynamic_cast 返回 0,即使它的参数不是 0。例如,当您将超类强制转换为子类(所谓的“向下强制转换”)时,就会发生这种情况。查看本教程了解更多信息:http://www.cplusplus.com/doc/tutorial/typecasting/

我可以想象,如果您列表中的元素具有通用(不相关)超类型,那么这可能是您的问题。

【讨论】:

  • 他,这实际上看起来像什么。我不知道。我要检查一下,但我觉得你可能是对的。谢谢你。将尽快报告。
【解决方案2】:

正如你所说,这很难说,但这里有两个想法。

您可以尝试开启guard malloc

或者,您可能会通过在可疑类(如 EnemySprite 的)解构器/构造器中放置一个静态 int 计数器来减少/增加,并在它低于零时中断/记录。

【讨论】:

  • 感谢您的回答;我会尝试保护malloc。然而;析构函数永远不会被调用;我到处都有断点和参考计数器;据我所知,EnemySprite 根本没有被摧毁,但它已经消失了......
【解决方案3】:

我只看到j的定义i是什么? 我相信它会在CCLog("Now enemy with %d is NULL :(", i); 之后崩溃 因为这条线已经被记录了,它肯定不会在这里崩溃。

【讨论】:

  • i 在这种情况下是 (int i=1000;i
  • @CharlesS :您的代码中是否有任何节点具有 1001 的标签,而不是其中一个 EnermySprite 已添加到您的 this 中?尤其是 EnermySprite 的一些孩子?
【解决方案4】:

CCObjects 默认受制于 AutoReleasePool,这意味着 Cocos2D-x 将管理何时释放对象。如果你对这些对象使用静态构造函数,你可以调用object->retain()和object->release(),这样你就可以自己管理内存了。

来源:http://www.cocos2d-x.org/projects/cocos2d-x/wiki/Reference_Count_and_AutoReleasePool_in_Cocos2d-x

【讨论】:

  • 是的,我这样做了,过去效果很好。这是来自另一个程序员的 Objective C 端口,似乎有些东西在那里。在这个项目使用保留/释放之前,我从来没有遇到过这个问题。提个醒;在这种情况下,从不调用对象。这就是我说的原因; '它就消失了'。我在 ->release() 和 delete o;... 上有断点
【解决方案5】:

如果有什么东西将敌人对象更改为 NULL,我会做的是在敌人的地址处设置一个数据断点(对于 1001)。比,

  1. 如果遇到断点,则可能是内存损坏。
  2. 如果断点未命中并且您得到 NULL,请深入了解 getChildByTag()。然后我要做的是用dynamic_cast&lt;EnemySprite*&gt;(this-&gt;getChildren()-&gt;objectAtIndex()) 替换this-&gt;getChildByTag(),检查是否有任何区别。

【讨论】:

    【解决方案6】:

    Build Settings-&gt;Other C Flags-&gt;Debug and add -o0 标记并尝试调试。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-30
      • 2015-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-28
      相关资源
      最近更新 更多