
on Fri Nov 21 2008, "Pete Bartlett" <pete-AT-pcbartlett.com> wrote:
on Fri Nov 21 2008, Tomas Puverle <Tomas.Puverle-AT-morganstanley.com> wrote:
I decided to split off this part of another thread to try to get a consensus on the changes that occurred in Boost.Range with boost 1.35. The background is discussed elsewhere. What I'd like to do here is to come to an agreement with Thorsten and other developers on the following issues:
1) Is the change in the behaviour of Boost.Range in fact a defect? 2) What should be done about it?
Here are the reasons why I think Boost.Range is broken:
I think you're assuming way too much about people's familiarity with the problems. The things you are saying sound serious, but I certainly don't know enough about the way Range used to work and the nature of the change to evaluate most of what you wrote here. Please lay out, specifically, how things used to work and how they work now.
Thanks,
I'll let Tomas answer for himself fully. But in short:
You used to be able to call member functions on default-constructed iterator_ranges, now you cannot. [Apologies for the hard-coded paths in the following code]:
---
//#include "c:/boost/boost_1_34_0/boost/range/iterator_range.hpp" #include "c:/boost/boost_1_36_0/boost/range/iterator_range.hpp"
#include <vector> #include <iostream> #include <cstddef>
int main() { boost::iterator_range< std::vector<int>::const_iterator> r;
bool b1 = r.empty(); //returns true in 1.34, //asserts in debug 1.35+, undefined behaviour in release std::size_t b2 = r.size(); //returns 0 in 1.34 , //asserts in debug 1.35+, undefined behaviour in release
std::cout << "\n\n" << b1 << b2 << "\n\n"; }
I certainly agree that silently dropping that guarantee is a serious mistake. However, I'm not convinced the new behavior isn't the right design. There's a reason that default constructed iterators aren't required to behave except under assignment and destruction. The old design seems to have been trying to correct something that wasn't broken in the first place, at the cost of both space and time. If people want an iterator_range with an empty state that consumes storage and must be checked for on nearly every access, it should probably be a different class template. Or vice-versa. I don't particularly care if the non-checking one is called "range<>" or "iterator_range<>," but if I decide to make a std::vector of [iterator_]range<std::list<int>::iterator>, I sure don't want to pay for more than 2 int*s per element. -- Dave Abrahams BoostPro Computing http://www.boostpro.com