BOOST_FOREACH在使用“break”时进入无限循环?

5
下面的代码段在 BOOST_FOREACH 语句内部进入了一个无限循环,我无法弄清楚原因。根据 Boost 文档,好像在 BOOST_FOREACH 循环内部使用 "break" 是可以的。您知道可能出了什么问题吗?
std::vector<std::wstring> sectors = getSectors();
if (!_sectorCodes.empty()) {  // _sectorCodes is a std::set<std::wstring>.
    bool ok = false; // did we find the sector code we wanted?
    BOOST_FOREACH(Symbol sector, sectors) {
        if (_sectorCodes.find(sector) != _sectorCodes.end()) {
            ok = true;
            break;
        }
    }
    if (!ok) return NULL;
}

如果我用一个for循环(使用从sectors.begin()到sectors.end()的迭代器)替换BOOST_FOREACH循环,则它可以正常工作(没有无限循环)。
版本和其他信息:
- Boost: 1.40.0 - gcc: 4.1.2 - 架构:x86_64 - 只有在发布版本中才会出现此行为;如果我进行调试构建,则它按预期工作。 - 在Visual Studio下编译时,它按预期工作,即没有无限循环。
响应mkb的问题,这是当我运行gcc -E时得到的结果:
if (!_sectorCodes.empty()) {
 bool ok = false;
 if (boost::foreach_detail_::auto_any_t _foreach_col148 = boost::foreach_detail_::contain( (sectors) , (true ? 0 : boost::foreach_detail_::or_( boost::foreach_detail_::and_( boost::foreach_detail_::not_(boost::foreach_detail_::is_array_(sectors)) , (true ? 0 : boost::foreach_detail_::is_rvalue_( (true ? boost::foreach_detail_::make_probe(sectors) : (sectors)), 0))) , boost::foreach_detail_::and_( boost::foreach_detail_::not_(boost_foreach_is_noncopyable( boost::foreach_detail_::to_ptr(sectors) , boost_foreach_argument_dependent_lookup_hack_value)) , boost_foreach_is_lightweight_proxy( boost::foreach_detail_::to_ptr(sectors) , boost_foreach_argument_dependent_lookup_hack_value)))))) {} else if (boost::foreach_detail_::auto_any_t _foreach_cur148 = boost::foreach_detail_::begin( _foreach_col148 , (true ? 0 : boost::foreach_detail_::encode_type(sectors, boost::foreach_detail_::is_const_(sectors))) , (true ? 0 : boost::foreach_detail_::or_( boost::foreach_detail_::and_( boost::foreach_detail_::not_(boost::foreach_detail_::is_array_(sectors)) , (true ? 0 : boost::foreach_detail_::is_rvalue_( (true ? boost::foreach_detail_::make_probe(sectors) : (sectors)), 0))) , boost::foreach_detail_::and_( boost::foreach_detail_::not_(boost_foreach_is_noncopyable( boost::foreach_detail_::to_ptr(sectors) , boost_foreach_argument_dependent_lookup_hack_value)) , boost_foreach_is_lightweight_proxy( boost::foreach_detail_::to_ptr(sectors) , boost_foreach_argument_dependent_lookup_hack_value)))))) {} else if (boost::foreach_detail_::auto_any_t _foreach_end148 = boost::foreach_detail_::end( _foreach_col148 , (true ? 0 : boost::foreach_detail_::encode_type(sectors, boost::foreach_detail_::is_const_(sectors))) , (true ? 0 : boost::foreach_detail_::or_( boost::foreach_detail_::and_( boost::foreach_detail_::not_(boost::foreach_detail_::is_array_(sectors)) , (true ? 0 : boost::foreach_detail_::is_rvalue_( (true ? boost::foreach_detail_::make_probe(sectors) : (sectors)), 0))) , boost::foreach_detail_::and_( boost::foreach_detail_::not_(boost_foreach_is_noncopyable( boost::foreach_detail_::to_ptr(sectors) , boost_foreach_argument_dependent_lookup_hack_value)) , boost_foreach_is_lightweight_proxy( boost::foreach_detail_::to_ptr(sectors) , boost_foreach_argument_dependent_lookup_hack_value)))))) {} else for (bool _foreach_continue148 = true; _foreach_continue148 && !boost::foreach_detail_::done( _foreach_cur148 , _foreach_end148 , (true ? 0 : boost::foreach_detail_::encode_type(sectors, boost::foreach_detail_::is_const_(sectors)))); _foreach_continue148 ? boost::foreach_detail_::next( _foreach_cur148 , (true ? 0 : boost::foreach_detail_::encode_type(sectors, boost::foreach_detail_::is_const_(sectors)))) : (void)0) if (boost::foreach_detail_::set_false(_foreach_continue148)) {} else for (Symbol sector = boost::foreach_detail_::deref( _foreach_cur148 , (true ? 0 : boost::foreach_detail_::encode_type(sectors, boost::foreach_detail_::is_const_(sectors)))); !_foreach_continue148; _foreach_continue148 = true) {
  if (_sectorCodes.find(sector) != _sectorCodes.end()) {
   ok = true;
   break;
  }
 }
 if (!ok) return PatternFeatureSet_ptr();
}

这个扩展的一个显著特点是有两个嵌套的for循环。我无法弄清楚内部循环和外部循环发生了什么,但是否可能(正如David所建议的那样)我只是从内部循环中退出,并且BOOST_FOREACH由于某种原因没有处理得很好?


为什么不使用C++11的范围for循环呢? - BЈовић
我有一些外部限制,限制了我可以使用哪些编译器版本,包括多种架构;不幸的是,这意味着我不能使用c++11;我只能使用c++98。 - Edward Loper
C++98还是C++03?好的,我错过了编译器的版本。它是C++03。 - BЈовић
1
我不清楚BOOST_FOREACH的规则,但如果你使用任何带有“for each”名称的东西,然后使用break来离开循环,那么你就是在欺骗读者。 - James Kanze
1
@EdwardLoper:感谢您提供的预处理器输出,但很遗憾它并没有帮助太多,因为问题更可能是由于优化引起的...如果是LLVM,我会要求IR,但是由于是gcc,我们只能使用汇编了。您可以使用“-S”来转储生成的汇编代码。如果您能在尽可能小的函数中隔离出问题,然后再进行操作,那就太好了,然后请给我们该函数的汇编清单(启用优化)...也许一些老练的x86汇编黑客会在那里发现问题。 - Matthieu M.
显示剩余5条评论
1个回答

4

我打赌简化这个函数:

std::wstring const* find(std::vector<Symbol> const& sectors) {
    if (!_sectorCodes.empty()) {
        BOOST_FOREACH(Symbol sector, sectors) {
            std::set<Symbol>::const_iterator it = _sectorCodes.find(sector);
            if (it != _sectorCodes.end()) { return &*it; }
        }
    }
    return NULL;
} // find

解决了这个问题。

虽然有优化,但很难知道......但至少你的代码会更易读。我没有你的版本的gcc进行测试,而且我的(或clang)从来没有出过任何问题,所以我只能建议:x


好的,这个代码块在一个函数中间(也就是说,我不只是返回结果,还要对它进行其他操作),所以我需要添加一个辅助函数来完成这个任务——但这可能就是正确的做法。但我主要的问题不是针对这个特定的情况,而是关于我是否可以信任BOOST_FOREACH按照我的预期执行。 - Edward Loper
1
@EdwardLoper:你可以相信BOOST_FOREACH,但你能相信你的编译器吗……这是另一个问题 :x - Matthieu M.
太对了。但通常我可以信任boost来正确处理和掩盖我的编译器的缺陷。 :) - Edward Loper

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接