Boost logo

Boost Users :

Subject: Re: [Boost-users] Reverse for loop with boost::adaptors::reverse crashes
From: Filip Konvička (filip.konvicka_at_[hidden])
Date: 2014-11-28 04:03:06


> This works (albeit possibly with a performance penalty in the form of a
> double copy; I'm not sure if the compiler can be smart enough to elide
> that):
>
> template<typename T, typename R>
> std::vector<T> as_vector(const R& range)
> {
> return std::vector<T>(boost::begin(range), boost::end(range));
> }
>
> ...
>
> for (int i : as_vector<int>(boost::adapters::reverse(getv())))
>

Thanks, this might be helpful.

I am using the following when I write functions that return a range of
any_iterators to something that is a temporary vector:

namespace detail {
   template<typename PBackupVector, typename I>
   struct it_PXYZ_Backup2 : public I {
     /// A shared pointer to the backup container.
     /// The backup container is deleted with the last iterator to it.
     PBackupVector pBK;
     /// Construction - increment use count of the container,
     /// and copy the real iterator.
     it_PXYZ_Backup2(PBackupVector const& pBK, I const& it)
       : I(it)
       , pBK(pBK)
     {}
   };
}
/// Copies the container contents to a temporary vector and returns
/// iterator range over the copy.
/// The temporary vector is automatically removed when the last
/// iterator is destroyed.
template<typename it_PXYZ, typename C>
iterator_range<it_PXYZ>
iterators_from_copy(C const& container) {
   typedef std::vector<typename C::value_type> BackupVector;
   typedef shared_ptr<BackupVector> PBackupVector;
   PBackupVector pBackupVector =
     PBackupVector(new BackupVector(container.begin(), container.end()));
   typedef detail::it_PXYZ_Backup2<
     PBackupVector, typename BackupVector::const_iterator> it;
   return boost::make_iterator_range(
     it_PXYZ(it(pBackupVector, pBackupVector->begin())),
     it_PXYZ(it(pBackupVector, pBackupVector->end())));
}

You can then e.g.

iterator_range<it_PXYZ> getFiltered(std::vector<PXYZ> const& all) {
   std::vector<PXYZ> filtered;
   std::copy_if(all.begin(), all.end(), filtered.end(), ....);
   return iterators_from_copy<it_PXYZ>(filtered);
}

> It might be easier just to rewrite it like this though, which will
> satisfy the lifetime requirement while avoiding the possible performance
> penalty:
>
> auto v = getv();
> for (int i : boost::adapters::reverse(v)) {...}

That is what I would do at the moment.

By the way, I started a discussion on the topic at
comp.lang.c++.isocpp.general - "Range-based for loop temporaries
lifetime". There are some interesting comments on the subject there.

Cheers,
Filip


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net