神秘的海森虫?

发布于 2024-09-19 01:35:33 字数 2144 浏览 2 评论 0原文

所以我正在制作一个带有传送和普通鼠标的贪吃蛇游戏。我有一个这样运行的循环:

while(snake.alive() && miceEaten < micePerLevel)
{
    displayInfo(lives, score, level, micePerLevel - miceEaten);
    //some code
    if(miceEaten())
    {
        //update score...
    }
    //more stuff...
}

上面代码的问题是 displayInfo 在分数更新之前被调用,因此在吃掉鼠标后,用户必须等到循环再次运行才能查看他的分数更新。所以我将这一行代码移到了函数的底部:

while(snake.alive() && miceEaten < micePerLevel)
{
    //some code
    if(miceEaten())
    {
        //update score...
    }
    //more stuff...
    displayInfo(lives, score, level, micePerLevel - miceEaten);
}

传送停止工作!每当蛇到达传送点时,程序就会崩溃。 displayInfo 使用以下代码:

stringstream s;
s << "LEVEL " << left << setw(12) << level << "LIVES: " << setw(12) << lives << "MICE LEFT: " << setw(12) << miceLeft
    << "SCORE: " << setw(13) << score;
printLine(0, s.str(), WHITEONBLUE);

其中 printLine 只有 color_setmvprintwrefresh( )。与传送无关。诡异的。

因此,我转到了 Snake 函数,蛇从传送中获取下一个位置:

    body.push_back(teleports[overlap(next)]->teleportFrom(dir)); //next is a Location object

其中 teleports[overlap(next)]->teleportFrom(dir) 返回蛇要传送到的位置。为了找出崩溃的原因(也许 Teleport 返回屏幕外的某个位置?),我在上面的行之前添加了以下 3 行:

    Location l = teleports[overlap(next)]->teleportFrom(dir);
    mvprintw(1, 0, "(%i, %i)", l.x, l.y);
    refresh();

问题就消失了!

不仅如此,我还必须拥有这三行。如果我注释掉 mvprintw(1, 0, "(%i, %i)", lx, ly);refresh(); 或两者,则程序在到达传送时像以前一样崩溃。

关于可能导致这种行为的原因有什么想法吗?

更新:我尝试删除所有警告(主要是有关有符号/无符号数字比较的警告),但到目前为止仅保留 1 个:

warning: reference to local variable 'other' returned

代码:

Location& Location::operator = (Location other)
{
    if(this == &other)
        return other;
    x = other.x;
    y = other.y;
    return *this;
}

我该怎么做才能修复此警告?

So I'm making a snake game with teleports and the usual mice. I had a loop running like this:

while(snake.alive() && miceEaten < micePerLevel)
{
    displayInfo(lives, score, level, micePerLevel - miceEaten);
    //some code
    if(miceEaten())
    {
        //update score...
    }
    //more stuff...
}

The problem with the above code was that displayInfo gets called before the score gets updated, and so after eating a mouse, the user has to wait until the loop runs again to see his score updated. So I moved that one line of code to the bottom of the function:

while(snake.alive() && miceEaten < micePerLevel)
{
    //some code
    if(miceEaten())
    {
        //update score...
    }
    //more stuff...
    displayInfo(lives, score, level, micePerLevel - miceEaten);
}

and teleports stop working! The program crashes whenever the snake reaches a teleport. And displayInfo uses the following code:

stringstream s;
s << "LEVEL " << left << setw(12) << level << "LIVES: " << setw(12) << lives << "MICE LEFT: " << setw(12) << miceLeft
    << "SCORE: " << setw(13) << score;
printLine(0, s.str(), WHITEONBLUE);

Where printLine only has a color_set, mvprintw, and refresh(). Nothing to do with Teleports. Weird.

So I went to the snake function where the snake gets its next location from a teleport:

    body.push_back(teleports[overlap(next)]->teleportFrom(dir)); //next is a Location object

Where teleports[overlap(next)]->teleportFrom(dir) returns the location the snake is to be teleported to. In an attempt to see why it was crashing (perhaps Teleport was returning some location offscreen?), I added the following 3 lines before the above line:

    Location l = teleports[overlap(next)]->teleportFrom(dir);
    mvprintw(1, 0, "(%i, %i)", l.x, l.y);
    refresh();

And the problem disappears!

Not only that, but I HAVE to have those three lines. If I comment out mvprintw(1, 0, "(%i, %i)", l.x, l.y);, or refresh();, or both, the program crashes as before upon reaching a teleport.

Any ideas on what might be causing this behavior?

UPDATE: I tried removing all warnings (which were mostly warnings about comparisons of signed/unsigned numbers), but only 1 remains so far:

warning: reference to local variable 'other' returned

And the code:

Location& Location::operator = (Location other)
{
    if(this == &other)
        return other;
    x = other.x;
    y = other.y;
    return *this;
}

What do I do to fix this warning?

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

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

发布评论

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

评论(4

独留℉清风醉 2024-09-26 01:35:33

像这样构建你的赋值运算符:
您应该始终返回 *this (即使它们相等)。但自从您创建本地副本以来,他们永远不会这样做(所以这不是您的错误)。

Location& Location::operator = (Location const& other)
{
    // Does it really matter if you assign to self?
    x = other.x;
    y = other.y;
    return *this;
}

对于这样一个简单的类来说,标准的复制和交换似乎有点大材小用。

附言。您应该修复所有警告(即使它们像无符号不匹配一样简单)。如果您不修复它们,您将对其效力免疫,并且不会发现真正的问题,因为它周围都是您忽略的警告。因此,请修复所有这些问题(我总是打开标志,使编译器将所有警告视为错误,这样如果有任何警告,代码就不会编译)。

实现赋值运算符的正确方法(或者最普遍接受的好方法)。就是使用复制和交换习惯用法:

// notice the parameter is passed by value (i.e. a copy).
// So the copy part is aromatically taken care of here.
// So now you just need tom implement the swap() part of the idiom.
Location& Location::operator = (Location other)
{
    this->swap(other);
    return *this;
}

void Location::swap(Location& other)
{
    std::swap(x, other.x);
    std::swap(y, other.y);
}

Build your assignment operator like this:
You should always return *this (even if they were equal). But they never would since you were creating a local copy (so this was not your error).

Location& Location::operator = (Location const& other)
{
    // Does it really matter if you assign to self?
    x = other.x;
    y = other.y;
    return *this;
}

The standard copy and swap seemed a bit overkill for such a simple class.

PS. You should fix all warnings (even if they are as simple as the unsigned mismatch). If you do not fix them you will become immune to their potency and will not spot a real problem because it is surrounded by warning that you are ignoring. So fix them all (aI always turn on the flag that makes the compiler treat all warnings as errors so that the code does not compile if there are any warnings).

The correct way to implement assignment operator (or the most commonly accepted good way). Is to use the copy and swap idiom:

// notice the parameter is passed by value (i.e. a copy).
// So the copy part is aromatically taken care of here.
// So now you just need tom implement the swap() part of the idiom.
Location& Location::operator = (Location other)
{
    this->swap(other);
    return *this;
}

void Location::swap(Location& other)
{
    std::swap(x, other.x);
    std::swap(y, other.y);
}
冷夜 2024-09-26 01:35:33
Location& Location::operator = (Location other)
{
    if(this == &other)
        return other;
    x = other.x;
    y = other.y;
    return *this;
}

这将返回一个引用。当函数返回时,other 会发生什么? (它死了,而您没有提及任何内容。)由于这是您在问题区域周围处理的类,因此这可能就是原因。重新排列周围的代码会使堆栈处于某种条件下,在这种条件下引用死变量“有效”。

将其更改为return *this,或者干脆删除该检查。 (在现代 CPU 上,在没有分支的情况下分配两个变量可能总是比添加分支运行得更快。)

(通常还应该通过引用而不是通过值获取参数。)

Location& Location::operator = (Location other)
{
    if(this == &other)
        return other;
    x = other.x;
    y = other.y;
    return *this;
}

This returns a reference. When the function returns, what happens to other? (It dies, and you're referring to nothing.) Since this is the class you're dealing with around the problem area, this is probably the cause. Re-arranging surrounding code leaves the stack in a certain condition where referring to the dead variable "works".

Change it to return *this, or just remove the check altogether. (Assigning two variables without a branch will probably always run faster than adding a branch, on a modern CPU.)

(You should also generally take the parameter by reference, instead of by-value.)

夜夜流光相皎洁 2024-09-26 01:35:33

您检查过导致此异常的代码吗?这里引用的 Heisenbug 现象:

一个常见的例子是,在使用优化编译器编译的程序中出现错误,但在未经优化编译时(例如,为了生成调试模式版本)而编译的同一程序中则不会出现错误

以下是一些准则:

  • 竞争条件?你在使用线程吗?
  • 指针溢出边界某处?
  • 通过 valgrind 运行代码以监视内存缓冲区中任何异常/不稳定的变化

另一句话:

类似 heisenbug 行为的一个常见原因是,在调试模式下执行程序通常会在程序启动之前清理内存,并将变量强制放到堆栈位置,而不是将它们保存在寄存器中。这些执行上的差异可能会改变涉及越界成员访问或对内存初始内容的错误假设的错误的影响。另一个原因是调试器通常提供监视或其他用户界面,这些界面会导致执行附加代码(例如属性访问器),从而更改程序的状态。还有一个原因是核心上的 fandango,即指针越界的影响。在C++中,许多heisenbug是由未初始化的变量引起的。

确保开关已关闭 - 无优化、完整调试信息、清除任何现有版本、重新启动 IDE 并再次重新编译...

Have you checked your code that is causing this anomaly? The Heisenbug phenomena quoted here:

One common example is a bug that occurs in a program that was compiled with an optimizing compiler, but not in the same program when compiled without optimization (e.g., for generating a debug-mode version)

Here are a few guidelines:

  • Race condition? are you using threads?
  • Pointer overflow boundary somewhere?
  • Run your code through valgrind to monitor for any unusual/erratic changes in memory buffers somewhere

Another quote:

One common reason for heisenbug-like behaviour is that executing a program in debug mode often cleans memory before the program starts, and forces variables onto stack locations, instead of keeping them in registers. These differences in execution can alter the effect of bugs involving out-of-bounds member access or incorrect assumptions about the initial contents of memory. Another reason is that debuggers commonly provide watches or other user interfaces that cause additional code (such as property accessors) to be executed, which can, in turn, change the state of the program. Yet another reason is a fandango on core, the effect of a pointer running out of bounds. In C++, many heisenbugs are caused by uninitialized variables.

Ensure that the switches are turned off - no optimization, full debug information, clear any existing builds, restart the IDE and recompile again....

不喜欢何必死缠烂打 2024-09-26 01:35:33

首先,您的 Location::operator= 应该像这样:

Location& Location::operator = (const Location &other)
{
    if(this == &other)
        return *this;
    x = other.x;
    y = other.y;
    return *this;
}

但是,这可能无法解释崩溃。在大多数体系结构上,堆栈上的错误指针不会崩溃(假设 x 和 y 是 int)。

那么,这是曼德尔虫,而不是海森虫。你有其他人在某个地方破坏了记忆。祝你好运。

First of all, your Location::operator= should be like this instead:

Location& Location::operator = (const Location &other)
{
    if(this == &other)
        return *this;
    x = other.x;
    y = other.y;
    return *this;
}

However, that probably doesn't explain the crash. Bad pointers on stack here don't crash on most architectures (assuming x and y are int).

Now then, this is a mandelbug, not a heisenbug. You have somebody else somewhere corrupting memory. Good luck.

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