Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BOOST_FOREACH enters infinite loop when using "break"?

Tags:

c++

boost

c++03

The following code segment enters an infinite loop inside the BOOST_FOREACH statement, and I can't figure out why. As far as I can tell from the Boost documentation, it should be fine to use "break" inside a BOOST_FOREACH loop. Any idea what might be going wrong here?

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;
}

If I replace the BOOST_FOREACH loop with a for loop (using an iterator from sectors.begin() to sectors.end()), then it works just fine (no infinite loop).

Versions & additional info:

  • Boost: 1.40.0
  • gcc: 4.1.2
  • architecture: x86_64
  • I only get this behavior for release builds; if I do a debug build, then it works as expected.
  • When compiled under visual studio, it works as expected -- i.e., no infinite loop.

In response to mkb's question, here's what I get when I run 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();
}

One notable feature of this expansion is that there are two nested for loops. I'm not able to figure out what's going on in the inner vs outer loops, but is it possible that (as David suggests) I'm breaking out of just the inner loop, and BOOST_FOREACH isn't handling that quite right for some reason?

like image 417
Edward Loper Avatar asked Oct 08 '22 19:10

Edward Loper


1 Answers

I bet that simplifying the function:

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

solves the issue.

Although with optimizations, it's hard to know... but at least your code will be more readable. I don't have your version of gcc to test though, and never had any trouble with mine (or clang), so I can only suggest :x

like image 143
Matthieu M. Avatar answered Oct 10 '22 09:10

Matthieu M.