为什么我的迭代器指向null,但有时只是?

时间:2012-10-12 11:49:10

标签: c++

我需要编写一些类来在我的代码中实现Context Free Grammars。 CFG具有“左手侧 - >右手侧”格式的生产规则。它们实现如下:

class GrammarProduction{

  public:

  Nonterminal mLhs;
  std::vector<GrammarSymbol*> mRhs;

我想将生产规则存储在std :: set中,以确保没有人可以添加重复的规则。 为了使重复检测工作,我实现了运算符&lt;对于GrammarProductions,如下所示。

bool GrammarProduction::operator<(const GrammarProduction& other) const{
  if (mLhs < other.Lhs()) return true;
  if (mRhs.size() < other.Rhs().size()) return true;
  std::vector<GrammarSymbol*>::const_iterator it1, it2;
  it2 = other.Rhs().begin();
  for(it1 = mRhs.begin(); it1 != mRhs.end(); it1++){
    std::cout << (*it1) << std::endl;
    std::cout << (*it2) << std::endl;
    if(**it1 < **it2) return true;
    it2++;
  }
  return false;    
}

运行此代码会在行

处产生分段错误
    if(**it1 < **it2) return true;

因为指针* it2为null。但是,如果我将打印* it2的行更改为

    std::cout << (*it2) << other.Str() << std::endl;

它工作正常,* it2不为空。我不知道为什么会这样,任何建议都会受到高度赞赏。 如果有必要发布被调用的函数,我会这样做。我没有,因为我希望这个问题不重要,而且这个数字相当大(至少是一个帖子)。

编辑:我已经缩小了问题,归结为这个

bool GrammarProduction::operator<(const GrammarProduction& other) const{
  std::vector<GrammarSymbol*>::const_iterator it1, it2;

  it1 = mRhs.begin();
  std::cout << "it1:" << std::endl;
  std::cout << (*(mRhs.begin()))->Str() << std::endl; //output (1,2,2)
  std::cout << (*it1)->Str() << std::endl; //output (1,2,2)

  it2 = other.Rhs().begin();
  std::cout << "it2:" << std::endl;
  std::cout << (*(other.Rhs().begin()))->Str() << std::endl; //output (1,2,2)
  std::cout << (*it2)->Str() << std::endl; //Segmentation Fault

  //do whatever
  return false;
}

3 个答案:

答案 0 :(得分:2)

您应该在循环中检查it2 == other.Rhs().end()。如果将迭代器增加到最后一个元素之后,则取消引用它将无效并且可能会导致分段错误。

答案 1 :(得分:2)

您正在调用未定义的行为。由于您的Rhs()函数按值返回向量,因此它会在完整表达式的末尾被销毁:

//          vvvvv -- created here
it2 = other.Rhs().begin();
//          gone here -- ^

这使it2成为悬空迭代器,这与悬空指针基本相同。取消引用此迭代器将导致UB。要修复,请将返回类型作为引用:

std::vector<GrammarSymbol*>& Rhs(){ return mRhs; } // depending on your needs
std::vector<GrammarSymbol*> const& Rhs() const{ return mRhs; }

答案 2 :(得分:1)

if(**it1 < **it2) return true;
it2++;

不是很好,因为在你的for循环中你不会检查它是否到达列表的末尾。

应该有效的版本是:

bool GrammarProduction::operator<(const GrammarProduction& other) const{
  if (mLhs < other.Lhs()) return true;
  if (mRhs.size() < other.Rhs().size()) return true;
  std::vector<GrammarSymbol*>::const_iterator it1, it2;
  it2 = other.Rhs().begin();
  it2End = other.Rhs().end();
  for(it1 = mRhs.begin(); it1 != mRhs.end(); it1++){
    std::cout << (*it1) << std::endl;
    if (it2 == it2End ) return true;
    std::cout << (*it2) << std::endl;
    if(**it1 < **it2) return true;
    it2++;
  }
  return false; 

}