C++ 指针神秘地重置为空

C++ 指针神秘地重置为空,c++,pointers,C++,Pointers,我正在制作一个游戏,目前正在制作处理输入的部分。这里涉及三个类,一个是ProjectInstance类,它启动关卡和其他东西,一个是GameController,它将处理输入,另一个是PlayerEntity,它将受GameController确定的控件的影响。在开始关卡时,ProjectInstance创建GameController,并在步骤方法中调用EvaluateControls方法,该方法在游戏循环中调用。EvaluateControls方法看起来有点像这样: void CGameCo

我正在制作一个游戏,目前正在制作处理输入的部分。这里涉及三个类,一个是ProjectInstance类,它启动关卡和其他东西,一个是GameController,它将处理输入,另一个是PlayerEntity,它将受GameController确定的控件的影响。在开始关卡时,ProjectInstance创建GameController,并在步骤方法中调用EvaluateControls方法,该方法在游戏循环中调用。EvaluateControls方法看起来有点像这样:

void CGameController::EvaluateControls(CInputBindings *pib) {
    // if no player yet
    if (gc_ppePlayer == NULL) {
        // create it
        Handle<CPlayerEntityProperties> hep = memNew(CPlayerEntityProperties);
        gc_ppePlayer = (CPlayerEntity *)hep->SpawnEntity();
        memDelete((CPlayerEntityProperties *)hep);
        ASSERT(gc_ppePlayer != NULL);
        return;
    }

    // handles controls here
}
此函数被正确调用,断言从不触发。但是,每次调用此函数时,gc_ppePlayer都设置为NULL。正如您所看到的,它不是一个超出范围的局部变量。gc_ppePlayer可以设置为NULL的唯一位置是在构造函数中,也可能是在析构函数中,在调用EvaluateControls的过程中,这两个位置都不会被调用。调试时,gc_播放器在返回之前收到正确的预期值。当我再次按F10键且光标位于右大括号处时,该值将更改为0xFFFFFF。我在这里不知所措,怎么会这样?有人吗?

在gc\u ppePlayer==NULL上设置一个观察点,当该表达式的值更改为NULL或从NULL更改时,调试器会将您精确地指向它发生的位置

试试看会发生什么。寻找未终止的字符串或内存复制到内存太小等。。。通常,这是全局/堆栈变量被随机覆盖的问题的原因

brone在VS2005指令中添加观察点的步骤

转到断点窗口 单击新建, 单击数据断点。进来 &地址框中的玩家,离开 仅其他价值观。 然后跑。 当玩家改变时, 断点 将被击中勃朗

在gc_ppePlayer==NULL上设置一个观察点,当该表达式的值更改为NULL或从NULL更改时,调试器会将您精确地指向发生该事件的位置

试试看会发生什么。寻找未终止的字符串或内存复制到内存太小等。。。通常,这是全局/堆栈变量被随机覆盖的问题的原因

brone在VS2005指令中添加观察点的步骤

转到断点窗口 单击新建, 单击数据断点。进来 &地址框中的玩家,离开 仅其他价值观。 然后跑。 当玩家改变时, 断点 将被击中勃朗


您正在调试发行版还是调试配置?在版本构建配置中,您在调试器中看到的并不总是正确的。进行了优化,这可以使手表窗口显示您所看到的奇怪值

您是否真的看到了断言触发?断言通常由发布版本编译而成,所以我猜您正在调试发布版本,这就是为什么断言没有导致应用程序终止的原因

我建议构建一个调试版本的软件,然后查看gc_播放器是否真的为空。如果真的是这样,那么您可能会在重写该指针的地方看到某种内存堆损坏。但如果它是内存损坏,那么它通常不会像您描述的那样具有确定性


另外,像这样使用全局指针值通常被认为是不好的做法。如果它确实是单个对象并且需要全局可访问,请查看是否可以将其替换为singleton类。

是否正在调试发行版或调试配置?在版本构建配置中,您在调试器中看到的并不总是正确的。进行了优化,这可以使手表窗口显示您所看到的奇怪值

您是否真的看到了断言触发?断言通常由发布版本编译而成,所以我猜您正在调试发布版本,这就是为什么断言没有导致应用程序终止的原因

我建议构建一个调试版本的软件,然后查看gc_播放器是否真的为空。如果真的是这样,那么您可能会在重写该指针的地方看到某种内存堆损坏。但如果它是内存损坏,那么它通常不会像您描述的那样具有确定性


另外,像这样使用全局指针值通常被认为是不好的做法。如果它确实是单个对象并且需要全局可访问,请查看是否可以将其替换为singleton类。

我的第一个想法是,SpawnEntity返回指向内部成员的指针,该成员在调用memDelete时被清除。我不清楚指针何时设置为0xFFFFFF,但是如果它发生在调用memDelete期间,那么这就解释了为什么断言没有触发-0xFFFFFF与NULL不同

你重建了多久了 整个代码库?我经常看到这样的内存问题,只要重新构建整个解决方案就可以解决


您是否尝试过在功能结束时将步骤改为F11而不是F10?虽然您的示例没有显示任何局部变量,但为了简单起见,您可能遗漏了一些。如果是这样的话,F11将很有希望进入这些变量的析构函数,让您查看其中一个是否导致了问题。

我的第一个想法是,SpawnEntity正在返回一个指向内部成员的指针,该成员在调用memDelete时被清除。我不清楚指针何时设置为0xFFFFFF,但是如果它发生在调用memDelete期间,那么这就解释了为什么断言没有触发-0xFFFFFF与NULL不同

您重建整个代码库已经多久了?我经常看到这样的内存问题,只要重新构建整个解决方案就可以解决


您是否尝试过在功能结束时将步骤改为F11而不是F10?虽然您的示例没有显示任何局部变量,但为了简单起见,您可能遗漏了一些。如果是这样的话,F11将有希望进入这些变量的析构函数,让您查看其中一个是否导致了问题。

您的内核上有一个fandango

动态初始化是覆盖内存中的各种位

无论是直接的,还是间接的,全局文件都被覆盖。 相对于堆的全局内存在哪里

二进制切掉动态初始化的部分,直到问题消失。
每次注释一半,递归地

您的核心有一个fandango

动态初始化是覆盖内存中的各种位

无论是直接的,还是间接的,全局文件都被覆盖。 相对于堆的全局内存在哪里

二进制切掉动态初始化的部分,直到问题消失。
根据您所处的平台,递归地每次注释一半。有免费或付费的工具可以快速解决此类内存问题

不经意间:


根据您所在的平台,有免费或付费的工具可以快速解决此类内存问题

不经意间:



嗯,我到底在哪里做?我有一个手表对话,但我不认为这是你的意思。我使用的是Visual Studio 2005。我没有VS方面的经验,但任何值得使用的调试器都应该能够设置监视点,这对于值更改时触发的数据来说都是一个断点。您的下一个问题可能是如何在VS2005中设置观察点@hhafez-我不知道VS2005中的值何时变化是可以检测到的。我认为您只需在不同的关键位置设置断点,然后查看值是否已更改为所需的值。您也可以使用条件断点来实现这一点。在Visual Studio中,您可以通过设置条件断点来实现这一点。请参见。在VS中,右键单击右侧檐槽。设置条件断点的选项将出现。嗯,我应该在哪里做呢?我有一个手表对话,但我不认为这是你的意思。我使用的是Visual Studio 2005。我没有VS方面的经验,但任何值得使用的调试器都应该能够设置监视点,这对于值更改时触发的数据来说都是一个断点。您的下一个问题可能是如何在VS2005中设置观察点@hhafez-我不知道VS2005中的值何时变化是可以检测到的。我认为您只需在不同的关键位置设置断点,然后查看值是否已更改为所需的值。您也可以使用条件断点来实现这一点。在Visual Studio中,您可以通过设置条件断点来实现这一点。请参见。在VS中,右键单击右侧檐槽。设置条件断点的选项将出现。+1对于第一部分,正如我要说的,但是单例与全局数据反模式一样糟糕。在我的书中,简单的实例化和引用/指针更模块化。@Robert-我认为单例在被误用时可能是反模式,这通常是这样的。如果一个对象确实是系统中的单个对象,并且从法律上讲,它们不能超过一个,那么单例模式不是最适合使用的模式吗?比一个原始的指针/引用更好…IMHO,因为至少你可以跟踪对它的访问。是的,这确实是个问题。我之所以使用Release是因为调试无法启动,但当我最终解决了这个问题时,结果证明您是完全正确的。gc_ppePlayer根本没有有效的值。现在来找出原因:-p+1对于第一部分,正如我要说的,但在我的书中,单例和全局数据反模式一样糟糕。简单的实例化和引用/指针更模块化。@Robert-我认为单例
吨可能是反模式时,他们被滥用,这是经常发生的情况。如果一个对象确实是系统中的单个对象,并且从法律上讲,它们不能超过一个,那么单例模式不是最适合使用的模式吗?比一个原始的指针/引用更好…IMHO,因为至少你可以跟踪对它的访问。是的,这确实是个问题。我之所以使用Release是因为调试无法启动,但当我最终解决了这个问题时,结果证明您是完全正确的。gc_ppePlayer根本没有有效的值。现在找出原因:-p此函数中只有变量低于返回值,因此不会调用它们的析构函数。无论如何,我使用的SDK中的注释表示CreateEntity将实体与其属性绑定,以便在编辑器中内部使用,而SpawnEntity是单独的,用于在播放时创建实体。如果临时删除对memDelete的调用,会发生什么情况?指针是否保持不变?此函数中唯一的变量在返回值之下,因此不会调用它们的析构函数。无论如何,我使用的SDK中的注释表示CreateEntity将实体与其属性绑定,以便在编辑器中内部使用,而SpawnEntity是单独的,用于在播放时创建实体。如果临时删除对memDelete的调用,会发生什么情况?指针是否保持完好?