Is there a hoist-free version of BOOST_FOREACH?
I'm aware of the "hoisting" pitfall of BOOST_FOREACH where it caches the end iterator. However it seems that:
- Modifying sequences mid loop is fairly common (especially push_back)
- It wouldn't be hard to provide a version of BOOST_FOREACH that was didn't hoist so was immune to modification problems.
Clearly people often just write the loop by hand in these cases, but my question is this:
- Does such a version exist? something like BOOST_FOREACH_NOHOIST or some such.
I've thus far b开发者_运维问答een unable to find one.
Note: edited in response to Steve Jessop
"Modifying sequences mid loop is fairly common"
Avoiding the hoist would not make the macro immune to modification problems, since BOOST_FOREACH is also using a moving iterator under the covers that might be invalidated by push_back
(for example you're using a vector and it reallocates) or other structural modifications. Not much use getting a new, valid end
iterator if the thing you're comparing to it isn't valid any more.
It seems reasonable to me to provide something that obviously has problems with structural modifications. The pitfall says, "If doing so could cause iterators to become invalid, don't do it. Use a regular for loop instead.", without specifying which iterators need to remain valid. Use a for loop if your operations might break any iterator.
Providing something that sometimes has problems, depending on the nature of the modifications, means that the macro would have to document what modifications are OK and what aren't (if only by describing the hidden iterator and saying, "don't invalidate that, but you can invalidate other iterators"), which starts to become an awkward API. From a sample of one user, 100% assumed it would be immune, so I'm not sure it's a very intuitive interface.
That said, I think you're right that BOOST_FOREACH could easily guarantee that it only holds (1) the end iterator, plus (2) an iterator pointing at the current iterand. So if you had a hoist-free version, with (2) but not (1), then all you'd need to do is ensure you don't invalidate the current iterator. I don't think it exists, though, the author of that pitfall seems to consider the end iterator to be all part of the danger of invalidation, rather than trying to separate out different kinds of invalidation. I think BOOST_FOREACH
was intended as an improved syntax for std::for_each
over a Boost.Range, and meets that goal. You could always suggest to the relevant Boost people that it could be more than that.
精彩评论