【问题标题】:SIGSEGV signal while iterating a map in C++在 C++ 中迭代地图时发出 SIGSEGV 信号
【发布时间】:2012-12-17 06:34:27
【问题描述】:

我尝试解决这个问题大约 5 天,但没有运气,我尝试的每个解决方案都失败了。

我在下面找到了 SIGSEGV 的一些原因,但没有任何帮助 What is SIGSEGV run time error in C++?

好的,这里是代码。 我有 2 个实例,其中包含一些关键字特征及其分数

我想得到他们的欧几里得距离,这意味着我必须保存每个实例的所有关键字,然后找到第一个关键字与第二个关键字的差异,然后找到其余的差异二审的。我想要的是在迭代第一个地图时,能够从第二个地图中删除元素。由于我们有两个消息集合,因此会多次调用以下方法,并将第一个消息集合中的每条消息与第二个消息集合中的每条消息进行比较。

我有这段代码,但它突然停止了,尽管我检查了它在某些地方放置了多个 cout 的情况下工作了几秒钟

请注意,这是针对大学任务的,因此我不能使用 boost 和所有这些技巧。但我想知道绕过我遇到的问题的方法。

float KNNClassifier::distance(const Instance& inst1, const Instance& inst2) {   
map<string,unsigned> feat1;
map<string,unsigned> feat2;
for (unsigned i=0; i<inst1.getNumberOfFeatures(); i++) {
  feat1[inst1.getFeature(i)]=i;
}
for (unsigned i=0; i<inst2.getNumberOfFeatures(); i++) {
  feat2[inst2.getFeature(i)]=i;
}
float dist=0;

map<string,unsigned>::iterator it;
for (it=feat1.begin(); it!=feat1.end(); it++) {
  if (feat2.find(it->first)!=feat2.end()) {//if and only if it exists in inst2
    dist+=pow( (double) inst1.getScore(it->second) - inst2.getScore(feat2[it->first]) , 2.0);
    feat2.erase(it->first);
  }
  else {
    dist+=pow( (double) inst1.getScore(it->second) , 2.0);
  }
}

for (it=feat2.begin(); it!=feat2.end(); it++) {//for the remaining words
  dist+=pow( (double) inst2.getScore(it->second) , 2.0);
}
feat1.clear(); feat2.clear(); //ka8arizoume ta map gia thn epomenh xrhsh
return sqrt(dist);    
}

我也尝试了这个想法,以便不必删除某些内容,但它也突然停止了。

float KNNClassifier::distance(const Instance& inst1, const Instance& inst2) {
map<string,unsigned> feat1;
map<string,unsigned> feat2;
map<string,bool> exists;
for (unsigned i=0; i<inst1.getNumberOfFeatures(); i++) {
  feat1[inst1.getFeature(i)]=i;
}
for (unsigned i=0; i<inst2.getNumberOfFeatures(); i++) {
  feat2[inst2.getFeature(i)]=i;
  exists[inst2.getFeature(i)]=false;
  if (feat1.find(inst2.getFeature(i))!=feat1.end()) {
    exists[inst2.getFeature(i)]=true;
  }
}
float dist=0;
map<string,unsigned>::iterator it;
for (it=feat1.begin(); it!=feat1.end(); it++) {
  if (feat2.find(it->first)!=feat2.end()) {
    dist+=pow( (double) inst1.getScore(it->second) - inst2.getScore(feat2[it->first]) ,      2.0);
  }
  else {
    dist+=pow( (double) inst1.getScore(it->second) , 2.0);
  }
}

for (it=feat2.begin(); it!=feat2.end(); it++) {
  if(it->second==false){//if it is true, it means the diff was done in the previous iteration
    dist+=pow( (double) inst2.getScore(it->second) , 2.0);
  }
}

feat1.clear(); feat2.clear(); exists.clear();
return sqrt(dist);
}

【问题讨论】:

  • 您是否运行调试器来找到它崩溃的行?
  • Basilis,您显示的代码似乎格式正确。如果您不想浪费更多的时间,在调试器中运行它将是至关重要的。不要运行basilis_prog,而是运行gdb basilis_progr 将运行它直到它崩溃。 bt 会告诉你崩溃发生的确切位置。
  • 我使用 netbeans。我究竟如何使用 gdb 运行程序?调试器有什么技巧吗?
  • 你可以在netbeans中使用调试器。右键单击项目节点并选择“调试”。您现在可以看到它在哪里崩溃,甚至可以在您慢慢接近崩溃时检查正在发生的事情。如果您有特定的调试问题,请在此处发布。我们已经开始离开这个问题的初衷。您必须相信我,对许多此类问题的一般答案是“学习如何使用调试器”。
  • 好的,我有具体的问题。我运行调试器等待看到熟悉的东西,但我得到的只是这 2 [main] spam_filter 3520 exception::handle: Exception: STATUS_ACCESS_VIOLATION 686 [main] spam_filter 3520 open_stackdumpfile: Dumping stack trace to spam_filter.exe.stackdump

标签: c++ map iterator segmentation-fault


【解决方案1】:

代码本身似乎没问题(我认为我之前发现的错误不是一个)。然而, 可能有更简单的方法:

  1. 与其在第二个集合中查找第一个集合中的字符串,不如同时在两个列表中移动并将迭代器推进到较小的元素或两个迭代器(如果它们使用相同的字符串)。在每种情况下都直接进行相应的计算。
  2. 我个人会为此使用两个排序的std::vector&lt;std::pair&lt;std::string, unsigned int&gt; &gt;,但std::map&lt;std::string, unsigned int&gt; 也可以。

我无权访问您的 Instance 课程,因此尚未对其进行测试,但类似下面的内容应该可以工作。

struct compare1st {
    bool operator()(std::pair<std::string, unsigned int> const& p1,
                    std::pair<std::string, unsigned int> const& p2) const {
        return p1.first < p2.first;
    }
};

std::vector<std::pair<std::string, unsigned int> > fill(Instance const& inst) {
    std::vector<std::pair<std::string, unsigned int> > rc;
    for (unsigned int i(0), end(inst.getNumberOfFeatures()); i != end; ++i) {
        rc.push_back(std::make_pair(inst.getFeature(i), i));
    }
    std::sort(rc.begin(), rc.end(), compare1st());
    return rc;
}
double square(double d) { // pow(d, 2.0) is fairly expensive
    return d * d;
}

float KNNClassifier::distance(const Instance& inst1, const Instance& inst2) {   
    typedef std::pair<std::string, unsigned int> Pair;
    std::vector<Pair> feat1 = fill(inst1);
    std::vector<Pair> feat2 = fill(inst2);

    std::vector<Pair>::const_iterator it1(feat1.begin()), end1(feat1.end());
    std::vector<Pair>::const_iterator it2(feat2.begin()), end2(feat2.end());
    double result(0.0);
    while (it1 != end1 && it2 != end2) {
        if (it1 != end1 && (it2 == end2 || it1->first < it2->first)) {
            result += square(inst1.getScore((it1++)->second);
        }
        else if (it2 != end2 && (it1 == end1 || it2->first < it1->first))
            result += square(inst2.getScore((it2++)->second);
        }
        else {
            result += square(inst1.getScore((it1++)->second)
                             -  inst2.getScore((it2++)->second);
        }
    }
    return sqrt(result);
}

【讨论】:

  • 这似乎不是问题。他在值上调用了擦除,在另一个容器中,而不是在同一个容器的迭代器上。
  • Basilis 在字符串上使用 erase(),而不是迭代器。此外,map::erase(iterator) 有一个 void 返回类型。
  • @DrewDormann:第一点是正确的,但我以某种方式得出结论,它是在它所在的地图上调用的,查找对象没有多大意义。第二点对于 C++ 2011 肯定是不正确的,尽管它对于 C++ 2003 是正确的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-04
  • 1970-01-01
  • 1970-01-01
  • 2018-05-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多