我需要编写一些类来在我的代码中实现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;
}
答案 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;
}