g++优化使程序无法运行

g++ optimization makes the program unable to run

我实现了一个基于D*-Lite的路径规划算法。当我不打开优化(-O0)时,程序可以正常运行。但是当我打开优化级别(-O1/2/3)时,程序无法终止。在Visual Studio下,debug模式和release模式都可以正常运行。以上情况,代码都是一样。我不知道怎么找到问题,谁能帮帮我?

class DstarLite {
public:
  DstarLite() = delete;
  DstarLite(GridStatus* a, GridStatus* b, FILE* fp)
      : k_m_(0), start_(a), last_(start_), goal_(b), open_close_(fp) {}
  void calculateKey(GridStatus* s);
  void updateVertex(GridStatus* u);
  void initialize();
  void computeShortestPath();
  void rePlanning(vector<pair<GridStatus*, int>>& node_change);
  GridStatus* getStart();
  void setStart(GridStatus* val);
  GridStatus* getGoal();

private:
  Fib frontier_;  
  double k_m_;
  unordered_map<GridStatus*, handle_t>
      heap_map_;  
  GridStatus* start_;
  GridStatus* last_;  
  GridStatus* goal_;
  FILE* open_close_;
};

void DstarLite::calculateKey(GridStatus* s) {
  s->f = min(s->g, s->rhs) + heuristic(start_, s) + k_m_;
  s->k2 = min(s->g, s->rhs);
}

void DstarLite::initialize() {
  fprintf(open_close_, "%d %d\n", start_->x, start_->y);
  fprintf(open_close_, "%d %d\n", goal_->x, goal_->y);
  goal_->rhs = 0;
  calculateKey(goal_);
  handle_t hand = frontier_.push(goal_);
  heap_map_[goal_] = hand;
}

void DstarLite::updateVertex(GridStatus* u) {
  bool heap_in = heap_map_.find(u) != heap_map_.end();
  if (u->g != u->rhs && heap_in) {
    calculateKey(u);
    frontier_.update(heap_map_[u]);
  } else if (u->g != u->rhs && !heap_in) {
    calculateKey(u);
    handle_t hand = frontier_.push(u);
    heap_map_[u] = hand;
  } else if (u->g == u->rhs && heap_in) {
    calculateKey(u);
    frontier_.erase(heap_map_[u]);
    heap_map_.erase(u);
  }
}

void DstarLite::computeShortestPath() {
  int count = 0;
  while (smaller(frontier_.top(), start_) || !myEqual(start_->rhs, start_->g)) {
    count++;
    auto u = frontier_.top();
    pair<double, double> k_old = {u->f, u->k2};
    pair<double, double> k_new;
    k_new.first = min(u->g, u->rhs) + heuristic(start_, u) + k_m_;
    k_new.second = min(u->g, u->rhs);
    if (k_old < k_new) {
      calculateKey(u);
      frontier_.update(heap_map_[u]);
    } else if (myGreater(u->g, u->rhs)) {
      u->g = u->rhs;
      frontier_.pop();
      heap_map_.erase(u);
      for (auto s : neighbors(u)) {
        if (s->rhs > u->g + cost(u, s)) {
          s->next = u;
          s->rhs = u->g + cost(u, s);
          updateVertex(s);
        }
      }
    } else {
      double g_old = u->g;
      u->g = kDoubleInfinity;
      auto neighbor = neighbors(u);
      neighbor.push_back(u);
      for (auto s : neighbor) {
        if (myEqual(s->rhs, cost(s, u) + g_old)) {
          if (!equal(s, goal_)) {
            double pp_s = kDoubleInfinity;
            for (auto succ : neighbors(s)) {
              double dis = succ->g + cost(succ, s);
              if (dis < pp_s) {
                pp_s = dis;
                s->next = succ;
              }
            }
            s->rhs = pp_s;
          }
        }
        updateVertex(s);
      }
    }
  }
  cout << "Dstar visited nodes : " << count << endl;
}

void DstarLite::rePlanning(vector<pair<GridStatus*, int>>& node_change) {
  k_m_ += heuristic(last_, start_);
  last_ = start_;

  for (auto change : node_change) {
    GridStatus* u = change.first;
    int old_threat = u->threat;
    int new_threat = change.second;

    double c_old;
    double c_new;


    u->threat = new_threat;
    u->rhs += (new_threat - old_threat) * threat_factor;
    updateVertex(u);

    
    for (auto v : neighbors(u)) {
      u->threat = old_threat;
      c_old = cost(v, u);
      u->threat = new_threat;
      c_new = cost(v, u);
      if (c_old > c_new) {
        
        if (v != goal_) {
          if (v->rhs > u->g + c_new) {
            v->next = u;
            v->rhs = u->g + c_new;
          }
        }
      } else if (myEqual(v->rhs, c_old + u->g)) {
        if (v != goal_) {
          double pp_s = kDoubleInfinity;
          for (auto pre : neighbors(v)) {
            double dis = pre->g + cost(pre, v);
            if (dis < pp_s) {
              pp_s = dis;
              v->next = pre;
            }
          }
          v->rhs = pp_s;
        }
      }
      updateVertex(v);
    }
  }
}

GridStatus* DstarLite::getStart() { return start_; }

void DstarLite::setStart(GridStatus* val) { start_ = val; }

GridStatus* DstarLite::getGoal() { return goal_; }
  DstarLite dstar(start, goal, open_close);
  dstar.initialize();
  dstar.computeShortestPath();

抱歉,我觉得很难定位到代码中的问题,所以之前没有展示代码。现在重新编辑了题目,但是代码很多,主要调用部分是computeShortest().

由于您没有提供任何代码,我们只能给您一些一般提示来解决此类问题。

作为第一个假设,您的代码肯定存在一个或多个导致我们称之为 undefined behaviour UB 的错误。由于结果是未定义的,它可以是任何东西,并且经常随着不同的优化级别、编译器版本或平台改变行为。

你能做什么:

  • 启用所有警告并修复它们!特别寻找诸如“比较总是...”、“使用 xxx(有时)未初始化”、“无效指针转换”之类的内容,...

  • 尝试在不同的编译器上编译。您还应该尝试使用 gcc and/or clang,即使在 windows 上也是如此。第一次在 windows 平台上获取这些编译器 运行 的环境可能很难,但确实值得这样做。不同的编译器会给出不同的警告。修复来自所有编译器的所有警告是一个非常好的帮助!

  • 你应该使用像 valgrind 这样的内存跟踪器。我对 windows 的经验不多,但我相信也有这样的工具,也许已经集成到您的开发套件中了。这些工具非常适合查找“of by x”访问、访问释放的内存等问题。

  • 如果您仍然运行遇到这样的麻烦,静态代码分析器工具可能会有所帮助。通常不像管理人员认为的那么多,因为今天的编译器通过检测恐龙程序员所期望的缺陷要好得多。额外的发现通常是误报,尤其是当您使用现代 C++ 时。通常,您可以省下这笔钱并参加 class 的教育!

  • 评论,评论,与其他人一起评论!

  • 把问题剪短!您应该将大部分开发时间花在设置良好的自动化单元测试上。检查每个路径,每个文件中的每个函数。很高兴看到至少 95% 的分支被测试覆盖。如果您更改优化器级别和/或编译器和平台,如果您的代码中有 UB,通常这些测试也会失败。

  • 使用调试器可能会令人沮丧。在高度优化的代码中,您会跳过所有内容而什么都不会,您可能无法真正看到您在哪里以及与您的代码有什么关系。如果在较低的优化器级别中不存在错误,那么您实际上没有太多机会找到潜在的问题。

  • 最后但同样重要的是:“printf 调试”。但这也可能会改变行为。在最坏的情况下,如果您添加调试输出,代码将始终 运行。但这是一个机会!

  • 使用编译器中的线程和内存清理器。

问题是浮点数比较引起的。之前写代码的时候特意搁置了这个问题:)。修复后可以正常运行