【问题标题】:std::sort crashes with strict weak ordering - comparing with garbage valuesstd::sort 因严格的弱排序而崩溃 - 与垃圾值比较
【发布时间】:2019-04-23 16:15:04
【问题描述】:

我编写了一个比较函数,该函数应该在像国际象棋这样的游戏中比较玩家的两个可能的移动选项。每个 Move 都包含一个应该进行移动的图形和一个将移动的点。点已经被检查,所以它们都是有效的移动。当我尝试使用严格的弱排序和 std::sort 函数对包含当前可用的所有移动的列表进行排序时,在我的比较函数与一个移动中的一些垃圾图形指针发生冲突后,我得到一个 SIGSEG。

我已经尝试找出垃圾指针的来源,但我发现 std::sort 函数以某种方式将它与所有其他动作混合在一起。当我尝试使用 std::stable_sort 进行排序时,会发生相同的段错误。我也考虑过堆栈问题,因为我以前有过一些问题,但事实并非如此。

bool cmpWhite(White_Move m1, White_Move m2) {

    if (m1.f == nullptr) {
        return true;
    } else if (m2.f == nullptr) {
        return true;
    }

    int sum1 = 0;
    double avg1 = 0;
    Figure *f1 = m1.f;
    Point origin1 = f1->getCoordinatesAsPoint();
    int sum2 = 0;
    double avg2 = 0;
    Figure *f2 = m2.f;
    Point origin2 = f2->getCoordinatesAsPoint();

    Point p;

    movePiece(field_pub, f1, m1.p);
    std::vector<Point> moves = black_king->getAllNewPossiblePositions();
    for (int i = 0; i < moves.size(); i++) {
        p = moves[i];
        if (!black_king->isPositionBlocked(field_pub, p.x, p.y)) {
            sum1++;
            // avg1 += sqrt((p.x - target_pub.x) * (p.x - target_pub.x) + (p.y - target_pub.y) * (p.y - target_pub.y));
        }
    }
    p = black_king->getCoordinatesAsPoint();
    if (!black_king->isPositionBlocked(field_pub, p.x, p.y)) {
        sum1++;
    }
    // avg1 = (double)sum1;
    movePiece(field_pub, f1, origin1);

    movePiece(field_pub, f2, m2.p);
    moves = black_king->getAllNewPossiblePositions();
    for (int i = 0; i < moves.size(); i++) {
        p = moves[i];
        if (!black_king->isPositionBlocked(field_pub, p.x, p.y)) {
            sum2++;
            // avg2 += sqrt((p.x - target_pub.x) * (p.x - target_pub.x) + (p.y - target_pub.y) * (p.y - target_pub.y));
        }
    }
    p = black_king->getCoordinatesAsPoint();
    if (!black_king->isPositionBlocked(field_pub, p.x, p.y)) {
        sum2++;
    }
    // avg2 = (double)sum2;
    movePiece(field_pub, f2, origin2);
    std::cout << "cmp: " << sum1 << " " << sum2 << std::endl;
    return sum1 < sum2;
}
std::vector<White_Move> sortBestMovesForWhite(Figure **figures, int size, King *bKing, int **field, Point target) {
    target_pub = target;
    field_pub = new int *[FIELD_WIDTH];
    for (int x = 0; x < FIELD_WIDTH; x++) {
        field_pub[x] = new int[FIELD_HEIGHT];
        for (int y = 0; y < FIELD_HEIGHT; y++) {
            field_pub[x][y] = field[x][y];
        }
    }
    black_king = bKing;
    std::vector<White_Move> moves;
    for (int i = 0; i < size; i++) {
        Figure *f = figures[i];
        std::vector<Point> m_point = f->getAllNewPossiblePositions();
        for (int j = 0; j < m_point.size(); j++) {
            if (!f->isPositionBlocked(field, m_point.at(j).x, m_point.at(j).y)) {
                White_Move move = {f, m_point.at(j)};
                moves.push_back(move);
            }
        }
    }
    // std::stable_sort(moves.begin(), moves.end(), cmpWhite);
    std::sort(moves.begin(), moves.end(), cmpWhite);
    for (int x = 0; x < FIELD_WIDTH; x++) {
        delete[] field_pub[x];
    }
    delete[] field_pub;
    return moves;
}

【问题讨论】:

  • 显示的代码表明White_Move 类型可能正在管理原始指针。你实现rule of three/five/zero了吗?
  • White_Move 只是一个包含原始图形指针 f 和点 p 的结构
  • 另外,将被调用的其他方法已经过测试并按预期工作。

标签: c++


【解决方案1】:

比较函数开头的return true 之一应该是return falsestd::sort 的比较器必须满足此处指定的条件:https://en.cppreference.com/w/cpp/named_req/Compare。如果不是这种情况,std::sort 将有未定义的行为。

正确的实现应该类似于:

bool cmpWhite(White_Move m1, White_Move m2) {

    if (m1.f == nullptr) {
        return m2.f != nullptr;
    }
    if (m2.f == nullptr) {
        return false;
    }
    ...
}

【讨论】:

  • 我已经试过了。如果我检查 nullptr,排序算法会给我 cmp 函数一些其他没有有效值的随机地址,所以检查实际上有点过时了。此外,该问题仅在大约 100 次 std::sort 函数调用后出现。
猜你喜欢
  • 2018-08-04
  • 2018-04-17
  • 2013-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多