BOOST_FOREACH enters infinite loop when using "break"?

boost, c++, c++03

Solution

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

Problem

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?

Original source