1つには、終了イテレータを格納し、重要な操作をチェックするイテレータラッパーを作成することもできます。
たとえばiterator_facade
、簡潔にするためにブーストを使用し、アンダーフローをチェックしません。
#include <boost/iterator/iterator_facade.hpp>
#include <iterator>
#include <stdexcept>
template <class Iter>
class checked_iterator:
public boost::iterator_facade<
checked_iterator<Iter>,
typename std::iterator_traits<Iter>::value_type,
typename std::iterator_traits<Iter>::iterator_category
>
{
Iter it, end;
public:
checked_iterator(Iter it, Iter end): it(it), end(end) {}
void increment()
{
if (it == end) { throw std::range_error("checked_iterator: increment beyond end"); }
++it;
}
void decrement()
{
//TODO: this is not checked
--it;
}
bool equal(const checked_iterator& other) const
{
return it == other.it;
}
typename std::iterator_traits<Iter>::reference dereference() const
{
if (it == end) { throw std::range_error("checked_iterator: dereference end"); }
return *it;
}
void advance(typename std::iterator_traits<Iter>::difference_type n)
{
//TODO: not checked for underflow
if (std::distance(it, end) < n) { throw std::range_error("checked_iterator: advance beyond end"); }
it += n;
}
typename std::iterator_traits<Iter>::difference_type distance_to(const checked_iterator& other) const
{
return other.it - it;
}
Iter base() const { return it; }
};
//create checked_iterators from containers, could be overloaded for arrays
template <class Container>
checked_iterator<typename Container::iterator> checked_begin(Container& c)
{
return checked_iterator<typename Container::iterator>(c.begin(), c.end());
}
template <class Container>
checked_iterator<typename Container::const_iterator> checked_begin(const Container& c)
{
return checked_iterator<typename Container::const_iterator>(c.begin(), c.end());
}
template <class Container>
checked_iterator<typename Container::iterator> checked_end(Container& c)
{
return checked_iterator<typename Container::iterator>(c.end(), c.end());
}
template <class Container>
checked_iterator<typename Container::const_iterator> checked_end(const Container& c)
{
return checked_iterator<typename Container::const_iterator>(c.end(), c.end());
}
テストコードの例:
#include <vector>
#include <list>
#include <iostream>
int main()
{
typedef std::list<int> Container;
try {
Container v(10);
checked_iterator<Container::iterator> it = checked_begin(v);
std::advance(it, 6);
std::cout << *it << '\n';
std::advance(it, 4);
std::cout << *it << '\n';
const Container& r = v;
checked_iterator<Container::const_iterator> cit = checked_begin(r);
std::advance(cit, 11);
}
catch (const std::exception& e) {
std::cout << e.what() << '\n';
}
}
関数の実装に関しては、効率上の理由からsafe_advance
、これによりランダムアクセスイテレータと他のイテレータを区別することもできます。std::advance
#include <iterator>
#include <stdexcept>
namespace detail
{
template <class Iter>
void safe_advance_aux(
Iter& it, Iter end,
typename std::iterator_traits<Iter>::difference_type n,
std::random_access_iterator_tag
)
{
if (end - it < n) throw std::range_error("advance beyond end (ra)");
it += n;
}
template <class Iter, class Tag>
void safe_advance_aux(
Iter& it, Iter end,
typename std::iterator_traits<Iter>::difference_type n,
Tag
)
{
for (typename std::iterator_traits<Iter>::difference_type i = 0; i != n; ++i) {
if (it == end) throw std::range_error("advance beyond end");
++it;
}
}
}
template <class Iter>
void safe_advance(Iter& it, Iter end, typename std::iterator_traits<Iter>::difference_type n)
{
detail::safe_advance_aux(it, end, n, typename std::iterator_traits<Iter>::iterator_category());
}