【问题标题】:Getting SIGSEGV (segmentation fault) when overloading operator== c++重载 operator== c++ 时获取 SIGSEGV(分段错误)
【发布时间】:2019-07-24 23:56:57
【问题描述】:

我在函数 operator== 上收到 SIGSEGV 信号,但是我不知道为什么会这样。调试器显示其中一个参数没有其成员的值,但有一个默认构造函数结构。
我得到的信号是 bool operator==(const Pos& p, const Pos& d)
这是完整的文件。

#include <iostream>
#include <vector>
#include <map>
using namespace std;





int sgn(int x)
{
    return (x>0) - (x<0);
}




struct Pos
{
    int xpos;
    int ypos;
    Pos()
            :xpos{ 0 }, ypos{ 0 }
    {}
    Pos(int xp, int yp)
            :xpos(xp), ypos(yp)
    {}
    Pos(const Pos& p)
            :xpos(p.xpos), ypos(p.ypos)
    {}
    Pos& operator=(const Pos&);
    bool operator<(const Pos&) const;
};

---->bool operator==(const Pos& p, const Pos& d)<----
{
    return p.ypos == d.ypos && p.xpos == d.xpos;
}



bool Pos::operator<(const Pos& p)const
{
    return xpos < p.xpos && ypos < p.ypos;
}
Pos& Pos::operator=(const Pos& P)
{
    xpos = P.xpos;
    ypos = P.ypos;
    return *this;
}




class Figure
{
public:
    Figure()
            :pos(0, 0), is_protected(false), color(' ')
    {}
    Figure(const Pos&, char);
    virtual void fix_move_zone();
    bool is_protected;
    char color;
    Pos pos;
    vector<Pos> move_zone;
};
Figure::Figure(const Pos& A, char C)
        :pos(A), color(C), is_protected(false)
{}
void Figure::fix_move_zone()
{
    return;
}



////////////////////// Global Variables ///////////////////////////
map<Pos, Figure> G_Field;                                           //
bool G_black_king_UA = false;                                       // flag to know if black king is under attack
///////////////////////////////////////////////////////////////////


bool is_valid_move(Pos v)
{
    return (v.xpos)>0 && (v.ypos)>0;
}

istream& operator>>(istream& is, Pos p)
{
    char c;
    is >> c >> p.ypos;
    p.xpos = c - 'A' + 1;
    if (!is_valid_move(p) || G_Field.find(p) != G_Field.end()) cerr << "ERROR: Either there is no such position or it is taken";
    return is;
}








class King : public Figure
{
public:
    void fix_move_zone();
    King(Pos, char);
};
King::King(Pos p, char c) : Figure(p, c)
{
    G_Field[pos] = Figure(pos, color);
    for (int i = -1; i<2; i++)
    {
        for (int j = -1; j<2; j++)
        {
            if (is_valid_move(Pos(pos.xpos + i, pos.ypos + j))) move_zone.push_back(Pos(pos.xpos + i, pos.ypos + j));
        }
    }
}

void King::fix_move_zone()
{
    for (int i = 0; i<move_zone.size(); i++)
    {
        if (G_Field[move_zone[i]].color)
        {
            if (G_Field[move_zone[i]].is_protected)move_zone.erase(move_zone.begin() + i);
        }
    }
}


class Knight : public Figure
{
public:
    void fix_move_zone();
    Knight(Pos, char);
};
Knight::Knight(Pos p, char c)
        : Figure(p, c)
{
    G_Field[pos] = Figure(pos, color);
    for (int i = -2; i<3; i++)
    {
        for (int j = -2; j<3; j++)
        {
            if (abs(i) + abs(j) == 3 && is_valid_move(Pos(pos.xpos + i, pos.ypos + j))) move_zone.push_back(Pos(pos.xpos + i, pos.ypos + j));
        }
    }
}
void Knight::fix_move_zone()
{
    for (int i = 0; i<move_zone.size(); i++)
    {
        if (G_Field[move_zone[i]].color)
        {
            if (G_Field[move_zone[i]].color == color)G_Field[move_zone[i]].is_protected = true;
            else G_black_king_UA = true;
        }
    }
}


class Bishop : public Figure
{
public:
    void fix_move_zone();
    Bishop(Pos, char);
};
Bishop::Bishop(Pos p, char c)
        : Figure(p, c)
{
    G_Field[pos] = Figure(pos, color);
    for (int i = -7; i<8; i++)
    {
        for (int j = -7; j<8; j++)
        {
            if (abs(i) == abs(j) && is_valid_move(Pos(pos.xpos + i, pos.ypos + j))) move_zone.push_back(Pos(pos.xpos + i, pos.ypos + j));
        }
    }
}

void Bishop::fix_move_zone()
{
    for (int i = 0; i<move_zone.size(); i++)
    {
        if (G_Field[move_zone[i]].color)
        {
            for (int j = 0; j<move_zone.size(); j++)
            {
                if (i == j)continue;
                if (sgn((pos.xpos - move_zone[i].xpos)) == sgn((pos.xpos - move_zone[j].xpos)) && sgn(pos.ypos - move_zone[i].ypos) == sgn(pos.ypos - move_zone[j].ypos))
                {
                    if (abs(pos.xpos - move_zone[j].xpos)>abs(pos.xpos - move_zone[i].xpos) || abs(pos.ypos - move_zone[j].ypos)>abs(pos.ypos - move_zone[i].ypos))
                    {
                        if (G_Field[move_zone[i]].color == color)G_Field[move_zone[i]].is_protected = true;
                        else G_black_king_UA = true;
                        move_zone.erase(move_zone.begin() + j);
                    }
                }
            }
        }
    }
}




class Queen : public Figure
{
public:
    void fix_move_zone();
    Queen(Pos, char);
};
Queen::Queen(Pos p, char c)
        :Figure(p, c)
{
    G_Field[pos] = Figure(pos, color);
    for (int i = -7; i<8; i++)
    {
        if (is_valid_move(Pos(pos.xpos + i, pos.ypos)))
        {
            move_zone.push_back(Pos(pos.xpos + i, pos.ypos));
        }

        for (int j = -7; j<8; j++)
        {
            if (abs(i) == abs(j) && is_valid_move(Pos(pos.xpos + i, pos.ypos + j))) move_zone.push_back(Pos(pos.xpos + i, pos.ypos + j));
            if (is_valid_move(Pos(pos.xpos, pos.ypos + j))) move_zone.push_back(Pos(pos.xpos, pos.ypos + j));
        }
    }
}
void Queen::fix_move_zone()
{
    for (int i = 0; i<move_zone.size(); i++)
    {
        if (G_Field[move_zone[i]].color)
        {
            for (int j = 0; j<move_zone.size(); j++)
            {
                if (i == j)continue;
                if (sgn((pos.xpos - move_zone[i].xpos)) == sgn((pos.xpos - move_zone[j].xpos)) && sgn(pos.ypos - move_zone[i].ypos) == sgn(pos.ypos - move_zone[j].ypos))
                {
                    if (abs(pos.xpos - move_zone[j].xpos)>abs(pos.xpos - move_zone[i].xpos) || abs(pos.ypos - move_zone[j].ypos)>abs(pos.ypos - move_zone[i].ypos))
                    {
                        if (G_Field[move_zone[i]].color == color)G_Field[move_zone[i]].is_protected = true;
                        else G_black_king_UA = true;
                        move_zone.erase(move_zone.begin() + j);
                    }
                }
            }
        }
    }
}



int main()
{
    Pos Wking;
    Pos Wknight;
    Pos WBishop;
    Pos WQueen;
    Pos BKing;
    cout << "Please enter position of the figure in this format:ex. A 7 " << endl;
    cout << "Black King: ";
    cin >> BKing;
    King BKI(BKing, 'b');
    cout << "White King: ";
    cin >> Wking;
    King WKI(Wking, 'w');
    cout << "White Knight: ";
    cin >> Wknight;
    Knight WKN(Wknight, 'w');
    cout << "White Bishop: ";
    cin >> WBishop;
    Bishop WBI(WBishop, 'w');
    cout << "White Queen: ";
    cin >> WQueen;
    Queen WQU(WQueen, 'w');
    for (int i = 0; i<BKI.move_zone.size(); i++)
    {
        for (int j = 0; j<WQU.move_zone.size(); j++)
        {
            if (BKI.move_zone[i] == WQU.move_zone[j])
            {
                BKI.move_zone.erase(BKI.move_zone.begin() + i);
                break;
            }
        }
        for (int j = 0; j<WKN.move_zone.size(); j++)
        {
            if (BKI.move_zone[i] == WKN.move_zone[j])
            {
                BKI.move_zone.erase(BKI.move_zone.begin() + i);
                break;
            }
        }
        for (int j = 0; j<WBI.move_zone.size(); j++)
        {
            if (BKI.move_zone[i] == WBI.move_zone[j])
            {
                BKI.move_zone.erase(BKI.move_zone.begin() + i);
                break;
            }
        }
        for (int j = 0; j<WKI.move_zone.size(); j++)
        {
            if (BKI.move_zone[i] == WKI.move_zone[j])
            {
                BKI.move_zone.erase(BKI.move_zone.begin() + i);
                break;
            }
        }
    }
    if (!BKI.move_zone.size() && G_black_king_UA) cout << "Checkmate!" << '\n';
    else cout << "It is not a Checkmate!" << '\n';

    return 0;

}

任何帮助将不胜感激。

【问题讨论】:

  • 错误:'abs' 未声明
  • 如果您使用的是 linux,请尝试使用 valgrind 运行程序或在传递标志 -fsanitize=address 时重新编译。

标签: c++ operator-overloading operator-keyword segmentation-fault


【解决方案1】:

BKI.move_zone 中删除元素后,不能保证BKI.move_zone[i] 仍然有效。

我使用 GDB(调试器)运行您的代码,并为所有 5 个查询回答 A 7。 在这种情况下。 BKI.move_zone.size() 最初是 1。然后,在 WQU 循环中删除了一个元素。结果,现在BKI.move_zone 有0 个元素,在以后的循环中访问BKI.move_zone[i] 变得危险。

即使BKI.move_zone[i]在删除后仍然有效,您的代码也可能无法处理删除元素之后的元素。

要解决这个问题,你应该像这样改变循环

for (int j = 0; j<WQU.move_zone.size(); j++)
{
    if (BKI.move_zone[i] == WQU.move_zone[j])
    {
        BKI.move_zone.erase(BKI.move_zone.begin() + i);
        break;
    }
}

喜欢这个

bool erased = false; // add declaretion at the beginning of BKI loop

for (int j = 0; j<WQU.move_zone.size(); j++)
{
    if (BKI.move_zone[i] == WQU.move_zone[j])
    {
        BKI.move_zone.erase(BKI.move_zone.begin() + i);
        erased = true; // flag that erasure happened
        break;
    }
}
if (erased) { // if erasure happened, rerun the loop
    i--; // to cancel i++; in the BKI loop
    continue; // rerun the loop
}

请注意,由于擦除发生时循环会重新运行,因此您无需在每个循环开始时初始化erased

【讨论】:

    【解决方案2】:

    BKI.move_zone 为空,因为BKI.move_zone 的元素在循环中被擦除。 检查下面。

        for (int i = 0; i<BKI.move_zone.size(); i++)
        {
            for (int j = 0; j<WQU.move_zone.size(); j++)
            {
                if (BKI.move_zone[i] == WQU.move_zone[j])
                {
                    BKI.move_zone.erase(BKI.move_zone.begin() + i); // BKI.move_zone is empty
                    break;
                }
            }
            for (int j = 0; j<WKN.move_zone.size(); j++)
            {
                if (BKI.move_zone[i] == WKN.move_zone[j])  // BKI.move_zone[0] is not exist
                {
                    BKI.move_zone.erase(BKI.move_zone.begin() + i);
                    break;
                }
            }
        //...
        }
    

    BKI.move_zone[i] == WKN.move_zone[j]与下面相同。

    BKI.move_zone[i].operator==(WKN.move_zone[j])

    所以,operator==()this 无效。

    在循环中擦除元素是非常危险的,因为这可能是对“过去的”数据的尊重。这将是一种未定义的行为。

    感谢阅读。

    【讨论】:

      猜你喜欢
      • 2013-11-24
      • 2020-06-26
      • 2012-06-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-25
      • 1970-01-01
      • 2011-08-21
      • 2022-01-11
      相关资源
      最近更新 更多