После сильной боли и страданий я обнаружил очень странное поведение, когда std::distance никогда не возвращается, если задан диапазон boost::filter_iterator по сравнению с std::deque. По-видимому, проблема уникальна для GCC (6.1+) с оптимизацией -O3. Вот пример, демонстрирующий поведение с нарушением:
#include <string>
#include <deque>
#include <iterator>
#include <iostream>
#include <boost/iterator/filter_iterator.hpp>
struct Foo
{
std::string bar, s = "";
char a = '\0';
};
int main()
{
const std::deque<Foo> foos(14, {""});
const std::string test {};
const auto p = [test] (const auto& foo) { return foo.bar == test; };
using boost::make_filter_iterator;
const auto begin = make_filter_iterator(p, std::cbegin(foos), std::cend(foos));
const auto end = make_filter_iterator(p, std::cend(foos), std::cend(foos));
std::cout << std::distance(begin, end) << std::endl;
}
Некоторые наблюдения:
- GCC с оптимизацией
-O2или меньше возвращается, как ожидалось. - Clang (3.8) возвращает правильный ответ с любым уровнем оптимизации.
- Изменение
std::dequeдоstd::vectorилиstd::listприводит к ожидаемому поведению. -
14является критическим; что-то меньшее, и проблема исчезает. - Важна
sizeof(Foo); удалениеsилиaзаставляет проблему уйти. - Захват
testпо ссылке или просто сравнение с константным выражением (например,foo.bar == " ") приводит к нормальному поведению. - Предупреждений компилятора нет (с
-Wall -Wextra -pedantic). - Valgrind не сообщает об ошибках.
- Используйте
fsanitize=undefined, и проблема исчезнет.
Что происходит?