boost::range::detail::any_iterator doesn't play well with boost::zip_iterator

拥有回忆 提交于 2019-12-13 17:09:12

问题


Consider the following code:

#include <boost/iterator/zip_iterator.hpp>
#include <boost/range/detail/any_iterator.hpp>
#include <boost/tuple/tuple.hpp>
#include <iostream>
#include <vector>

typedef boost::range_detail::any_iterator<
  boost::tuple<int &, char &>,
  boost::random_access_traversal_tag,
  boost::tuple<int &, char &> &,
  std::ptrdiff_t
> IntCharIterator;

int main()
{
  std::vector<int> v1 = {1, 2, 3, 4, 5};
  std::vector<char> v2 = {'a', 'b', 'c', 'd', 'e'};

  auto it = IntCharIterator(boost::make_zip_iterator(
    boost::make_tuple(v1.begin(), v2.begin()))
  );
  auto end_ = IntCharIterator(boost::make_zip_iterator(
    boost::make_tuple(v1.end(), v2.end()))
  );

  for (; it != end_; ++it)
    std::cerr << it->get<0>() << " " << it->get<1>() << "\n";

  return 0;
}

It works as expected (i.e. prints "1 a\n2 b...") when compiled with no optimizations, but either segfaults or produces garbage when compiled with -O2 (with both clang-3.6.0 and gcc-4.9.2, boost 1.56.0) and I have no clue what's wrong.

Also, when IntCharIterator wrapper is removed, the code works as expected with either optimization level.

Does anyone know what is going on here?


回答1:


This is a bug in Boost.Range: #10493 Since 1.56, any_range with non-reference references can cause UB (warning: currently the bug tracker has an invalid SSL certificate). This was a regression introduced by the fix for bug #5816 any_range requires copyable elements.

The workaround, oddly enough, is to make your Reference template type parameter const:

typedef boost::range_detail::any_iterator<
  boost::tuple<int &, char &>,
  boost::random_access_traversal_tag,
  boost::tuple<int &, char &> const,    // 'const', no '&'
  std::ptrdiff_t
> IntCharIterator;

If you want the code to work with pre-1.56 versions you can use a preprocessor conditional:

typedef boost::range_detail::any_iterator<
  boost::tuple<int &, char &>,
  boost::random_access_traversal_tag,
#if BOOST_VERSION < 105600
  boost::tuple<int &, char &>,          // no '&'
#else
  boost::tuple<int &, char &> const,    // 'const', no '&'
#endif
  std::ptrdiff_t
> IntCharIterator;

Note that in any case the Reference template type parameter should not have a &; per the zip_iterator synopsis, the reference_type is the same as the value_type, as it is a tuple of references:

typedef reference value_type;


来源:https://stackoverflow.com/questions/30168375/boostrangedetailany-iterator-doesnt-play-well-with-boostzip-iterator

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!