【问题标题】:g++ optimization makes the program unable to rung++优化使程序无法运行
【发布时间】:2020-11-19 21:05:43
【问题描述】:

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

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()

【问题讨论】:

  • 代码中很可能存在错误,您依赖未定义的行为 (UB)。由于编译器/优化器可能假设您的代码没有未定义的行为,因此它可能会破坏您的代码,例如通过完全优化产生 UB 的代码路径。一个经典的例子是int x; ... if (x+1&lt;x) { overflow (); } - 因为整数溢出是UB,整个if-block 可能会被删除。将代码减少到重现错误的最小部分并提供Minimal, Reproducible Example,以便我们帮助您调试。

标签: c++ c++11 gcc g++


【解决方案1】:

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

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

你可以做什么:

  • 真正启用所有警告并修复它们!特别注意“比较总是......”,“使用 xxx(有时)没有初始化”,“无效指针转换”,......

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

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

  • 如果您仍然遇到此类问题,静态代码分析器工具可能会有所帮助。通常不像经理们认为的那样多,因为今天的编译器在检测缺陷方面要好得多,正如恐龙程序员所期望的那样。额外的发现通常是误报,特别是如果您使用现代 C++。通常,您可以省钱并为自己的教育参加课程!

  • 审查、审查、与其他人审查!

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

  • 使用调试器可能会令人沮丧。在高度优化的代码中,您一无所有,您可能看不到自己在哪里以及与您的代码有什么关系。如果在较低的优化器级别中不存在该错误,您就没有太多机会发现潜在的问题。

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

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

【讨论】:

  • 感谢您的建议。我尝试使用其中一些来调试。另外,我提交了代码。您可以帮我检查一下吗?
  • 是的,我采纳了。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-27
    • 1970-01-01
    • 2015-11-13
    • 2016-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多