2015-05-11 2 views
2

Рассмотрим следующий код:подталкивание :: Диапазон :: подробнее :: any_iterator не очень хорошо играть с усилением :: zip_iterator

#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; 
} 

Он работает, как ожидалось (то есть отпечатки «1 а \ n2 б .. . ") при компиляции без оптимизаций, но либо segfaults, либо создает мусор при компиляции с -O2 (с clang-3.6.0 и gcc-4.9.2, boost 1.56.0), и я не знаю, что не так.

Кроме того, если оболочка IntCharIterator удалена, код работает как ожидалось с любым уровнем оптимизации.

Кто-нибудь знает, что здесь происходит?

ответ

3

Это ошибка в Boost.Range: #10493 Since 1.56, any_range with non-reference references can cause UB (предупреждение: в настоящее время трекер ошибок имеет неверный сертификат SSL). Это была регрессия, введенная исправлением для bug #5816 any_range requires copyable elements.

Обходной, как ни странно, чтобы сделать ваш Reference ШАБЛОН параметра типа 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; 

Если вы хотите, чтобы код для работы с предварительно 1,56 версии вы можете использовать препроцессор условный:

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; 

Обратите внимание, что в любом случае параметр типа шаблона Reference должен быть не имеет &; согласно zip_iterator synopsis, то reference_type такая же, как value_type, так как это кортеж ссылок:

typedef reference value_type;