SIGSEGV 通过写入局部变量

SIGSEGV through writing to local variable

我目前在我的 C++ 项目中遇到了最奇怪的行为。我想做的是计算两个双向量之间的欧氏距离(嗯,实际上,双向量的向量,因此 m_Data[0].size()).

这是来源:

double NEAT::Behavior::Distance_To(NEAT::PhenotypeBehavior* other)
{  
  double sum = 0.0;

  for (int i = 0; i < m_Data[0].size() && i < other->m_Data[0].size(); i++) {
    double x1 = m_Data[0][i];
    double x2 = b->m_Data[0][i];
    double difference = x1 - x2;
    difference *= difference;
    sum += difference;
  }

  return sqrt(sum);
}

我最初将所有这些写在一行中,但我将其分开以找出错误。发生的事情是,在调用此函数几千次后,它会在 for 循环的最后一行抛出一个 SIGSEGV:

sum += difference;

我不知道这怎么会发生。我已经检查了堆栈跟踪,它来自 Distance_To(...) 函数并且它被精确地抛出到这一行。一旦我将其注释掉,一切都很好(但当然该功能将无法正常工作,哈哈)。每次我 运行 程序与相同的对象交互时,信号都会同时抛出。

非常感谢您的帮助。谢谢!

编辑:我已经通过在进入循环之前打印出所需的值来验证此方法中指针的完整性。所有值都正确打印。这是我用于调试目的的函数的完整版本:

double NEAT::Behavior::Distance_To(NEAT::PhenotypeBehavior* other)
{  
  double sum = 0.0;

  Behavior* b = (Behavior*) other;

  // Gets executed without any problems
  if (genomeid == 300 && b->genomeid == 399) {
    std::cout << "PROBLEM CASE" << std::endl; 
    std::cout << "Printing values for 300..." << std::endl;
    for (int i = 0; i < m_Data[0].size(); i++) std::cout << m_Data[0][i] << std::endl;
    std::cout << "Printing values for 399..." << std::endl;
    for (int i = 0; i < m_Data[0].size(); i++) std::cout << b->m_Data[0][i] << std::endl;
  }

  // Doesn't get executed
  if (m_Data[0].size() != other->m_Data[0].size()) {
    std::cout << "Different sizes, " << m_Data[0].size() << " and " << b->m_Data[0].size() << std::endl;
  }

 // SIGSEGV at size() call
 for (int i = 0; i < m_Data[0].size() && i < b->m_Data[0].size(); i++) {
    double x1 = m_Data[0][i];
    double x2 = b->m_Data[0][i];
    double difference = x1 - x2;
    difference *= difference;

    // If this line gets commented out, no SIGSEGV but the program starts behaving weirdly afterwards (suddenly different sizes after the faulty run)
    sum += difference;
  }

  return sqrt(sum);
}

ASAN and valgrind 是您应该用来确定此类错误根本原因的工具。尽管在第 sum += difference 行抛出错误,但您的实际错误可能在到达此点之前发生在其他地方,这会破坏您的记忆。这些工具将帮助您进行跟踪。

抱歉,我错过了一些我应该使用但没有用于初始化对象等的 MultiNEAT 框架函数。无论如何,非常感谢你们所有人,我学到了很多关于使用 valgrind 和 ASAN 的知识(两者都非常方便,我以前不知道它们中的任何一个!大声笑)甚至还有一些好文章可供阅读。呸!