调用非虚拟成员函数时发生访问冲突

发布于 2024-12-22 21:44:21 字数 1028 浏览 3 评论 0原文

我有一段代码运行了很多次,突然报告访问冲突。

for(std::list<Projectile>::iterator it = projectiles.begin(); it != projectiles.end();) {
    bool finished = ...

    // try to print address of collides(), prints always 1
    std::cout << &Projectile::collides << std::endl; 
    // here it crashes:
    if(it->collides(&hero)) { 
        std::cout << "Projectile hits " << hero.getName() << std::endl;
        finished = it->apply(&hero);
    }

    // ...
    if(finished) {
        it = projectiles.erase(it);
    } else {
        ++it;
    }
}

因此,VS 调试堆栈跟踪显示,在 if(it->collides(&hero)) { 行中,程序尝试调用 cdcdcdcd() 处的方法,这会导致访问违规。

根据 VS,it*ithero 是有效对象。

所以我假设cdcdcdcd()实际上应该是collides()。由于 Collides 是一种非虚拟方法,因此它的地址基本上不应该改变,或者?

问题是方法 collides() 在成功之前执行了几次,但突然它不再起作用了。

难道是地址改了?我是否覆盖了它?

请帮我!我也很欣赏有关此代码的任何问题的信息:)

I have some piece of code that runs many times and suddenly reports an access violation.

for(std::list<Projectile>::iterator it = projectiles.begin(); it != projectiles.end();) {
    bool finished = ...

    // try to print address of collides(), prints always 1
    std::cout << &Projectile::collides << std::endl; 
    // here it crashes:
    if(it->collides(&hero)) { 
        std::cout << "Projectile hits " << hero.getName() << std::endl;
        finished = it->apply(&hero);
    }

    // ...
    if(finished) {
        it = projectiles.erase(it);
    } else {
        ++it;
    }
}

So VS debug stacktrace says that in line if(it->collides(&hero)) { the program tries to call a method at cdcdcdcd() which causes the access violation.

it, *it and hero are valid objects according to VS.

So I assume that cdcdcdcd() should actually be collides(). Since collides is a non-virtual method its address should basically not change or?

The thing is that the method collides() is executed several times before successfully, but suddenly it does not work anymore.

Can it be that the address is changed? Have I overwritten it?

Please help me! Also I appreciate information on anything that is not fine with this code :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

温馨耳语 2024-12-29 21:44:21

0xcdcdcdcd 是 Win32 调试 CRT 堆使用的填充模式;假设您正在 Windows 上的调试器中运行,这可能是一个重要的线索。这里有一个不错的堆填充模式的解释

我的猜测是,您以某种方式使其他地方的迭代器无效,或者存在其他缓冲区溢出或悬空指针或其他问题。

应用程序验证程序可能有助于诊断此问题。您可能还想研究问题如何调试堆损坏错误中提到的其他内容?任何原因中的一些技术重载全局 new 和删除? (免责声明:目前我对两者都有最高评价的答案)。

如果您的 STL 库具有调试功能,它也可能有助于解决这个问题。例如,Metrowerks(现为 Freescale)Codewarrior 具有定义 _MSL_DEBUG,可用于构建标准库的版本(包括 std::list),该版本将检测迭代器失效等常见问题(需要一定的运行时成本)。

看起来 Visual Studio 有 调试迭代器支持< /a> 如果您正在使用它,这可能符合要求。

0xcdcdcdcd is a fill pattern used by the Win32 Debug CRT Heap; assuming you're running in a debugger on Windows, this may be a significant clue. There's a decent explanation of the heap fill patterns here.

My guess is you're somehow either invalidating the iterator elsewhere, or have some other buffer overflow or dangling pointer or other issue.

Application Verifier may help with diagnosing this. You may also want to look into the other things mentioned in the question How to debug heap corruption errors? or some of the techniques from Any reason to overload global new and delete? (disclaimer: at the moment I have the top-rated answer on both).

If your STL library has a debugging feature it may help ferret this out as well. Metrowerks (now Freescale) Codewarrior has the define _MSL_DEBUG, for example, that can be used to build a version of the standard libraries (including std::list) which will detect common issues like iterator invalidation (at some runtime cost).

It looks like Visual Studio has debug iterator support which might fit the bill, if you're using that.

半衬遮猫 2024-12-29 21:44:21

你的终止条件似乎是错误的[编辑:实际上它看起来是正确的,即使它仍然让我害怕。请参阅评论。]。当finished 变为 true 时,您将擦除当前的射弹,然后将迭代器设置为...某物。没有理由认为循环将在此时终止。它很可能最终要么开始指向列表之外,要么指向一个无效的对象(调试器并不总是这样标记)。

当你擦除射弹时,你应该使用“break”显式地离开循环。

Your termination condition seems wrong [EDIT: actually it looks correct, even if it still scares me. See comments.]. When finished becomes true, you erase the current projectile and then set the iterator to ... something. There is no reason to think that the loop will terminate at this point. It's is likely that it will eventually either start pointing outside of the list, or to an otherwise invalid object (which your debugger will not always flag as such).

When you erase the projectile, you should just explicitly leave the loop using "break".

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文