代码之家  ›  专栏  ›  技术社区  ›  wrongusername

神秘的海森堡?

  •  5
  • wrongusername  · 技术社区  · 16 年前

    所以我在做一个有远程传送和普通老鼠的蛇游戏。我有一个循环是这样运行的:

    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);
    }
    

    传送停止了!每当蛇到达传送门,程序就会崩溃。以及 显示信息 使用以下代码:

    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_set mvprintw ,和 refresh()

    所以我去了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)", l.x, l.y); 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;
    }
    

    如何修复此警告?

    4 回复  |  直到 7 年前
        1
  •  8
  •   Loki Astari    16 年前

    按以下方式构建赋值运算符:
    你应该始终返回*这个(即使它们相等)。但他们永远不会,因为你正在创建一个本地副本(所以这不是你的错误)。

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

    对于这样一个简单的类,标准的复制和交换似乎有点过头了。

    另外,您应该修复所有警告(即使它们像无符号不匹配一样简单)。如果你不修复它们,你将对它们的效力免疫,并且不会发现真正的问题,因为它被你忽略的警告所包围。因此,修复它们(aI总是打开标志,使编译器将所有警告视为错误,以便在出现任何警告时代码不会编译)。

    实现赋值运算符的正确方法(或最常用的好方法)。使用复制和交换习惯用法:

    // 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);
    }
    
        2
  •  4
  •   GManNickG    16 年前
    Location& Location::operator = (Location other)
    {
        if(this == &other)
            return other;
        x = other.x;
        y = other.y;
        return *this;
    }
    

    这将返回一个引用。当函数返回时,会发生什么 other ? (它死了,你什么也没说。)因为这是你在问题区域处理的类,这可能是原因。重新排列周围的代码会使堆栈处于某个特定的条件下,引用死变量“起作用”。

    把它改成 return *this

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

        3
  •  3
  •   t0mm13b    16 年前

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

    一个常见的例子是,在使用优化编译器编译的程序中出现错误,但在未进行优化的情况下编译(例如,用于生成调试模式版本)时,错误不会出现在同一程序中

    以下是一些指导原则:

    • 比赛条件?你在用线程吗?
    • 指针溢出边界在什么地方?
    • 运行代码 valgrind 监视内存缓冲区中的任何异常/不稳定变化

    另一句话:

        4
  •  1
  •   Joshua    16 年前

    首先,您的Location::operator=应该如下所示:

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

    现在,这是曼德尔巴格,不是海森巴格。你有其他人在破坏记忆。祝你好运。

    推荐文章