У меня есть класс шаблона AsIterator
, который принимает числовой тип, в этом примере просто int
, и преобразует его в итератор (++
и --
) и уменьшает число, а operator*
просто возвращает ссылку на него).
Это отлично работает , если он не был заключен в std::reverse_iterator
и скомпилирован с любой оптимизацией (-O
). Когда я оптимизирую двоичный файл, компилятор удаляет вызов разыменования reverse_iterator
и заменяет его каким-то странным значением. Следует отметить, что он еще делает правильное количество итераций. Это просто значение, полученное обратным итератором, который является мусором.
Рассмотрим следующий код:
#include <iterator>
#include <cstdio>
template<typename T>
class AsIterator : public std::iterator<std::bidirectional_iterator_tag, T> {
T v;
public:
AsIterator(const T & init) : v(init) {}
T &operator*() { return v; }
AsIterator &operator++() { ++v; return *this; }
AsIterator operator++(int) { AsIterator copy(*this); ++(*this); return copy; }
AsIterator &operator--() { --v; return *this; }
AsIterator operator--(int) { AsIterator copy(*this); --(*this); return copy; }
bool operator!=(const AsIterator &other) const {return v != other.v;}
bool operator==(const AsIterator &other) const {return v == other.v;}
};
typedef std::reverse_iterator<AsIterator<int>> ReverseIt;
int main() {
int a = 0, b = 0;
printf("Insert two integers: ");
scanf("%d %d", &a, &b);
if (b < a) std::swap(a, b);
AsIterator<int> real_begin(a);
AsIterator<int> real_end(b);
for (ReverseIt rev_it(real_end); rev_it != ReverseIt(real_begin); ++rev_it) {
printf("%d\n", *rev_it);
}
return 0;
}
Это должно, по-видимому, зацикливаться от самого высокого вставленного числа до самого низкого и напечатать его, например, в этом прогоне (скомпилировано с -O0
):
Insert two integers: 1 4
3
2
1
То, что я получаю с -O
, вместо этого:
Insert two integers: 1 4
1
0
0
Вы можете попробовать в Интернете здесь; цифры могут меняться, но они всегда "неправильны" при оптимизации двоичного файла.
Что я пробовал:
- жесткого кодирования целых чисел ввода достаточно, чтобы получить тот же результат;
- проблема сохраняется с gcc 5.4.0 и clang 3.8.0, также при использовании libС++;
- создание всех объектов
const
(т.е. возвращениеconst int &
и объявление всех переменных как таковых) не исправляет его; - с помощью
reverse_iterator
таким же образом, например, некоторыеstd::vector<int>
отлично работают; - Если я просто использую
AsIterator<int>
для нормального цикла вперед или назад, он отлично работает. - в моих тестах, постоянная
0
, которая напечатана, на самом деле жестко запрограммирована компилятором, вызовыprintf
выглядят так, как только они скомпилированы с-S -O
:
movl $.L.str.2, %edi # .L.str.2 is "%d\n"
xorl %eax, %eax
callq printf
Учитывая последовательность поведения clang и gcc, я уверен, что они делают это правильно, и я неправильно понял, но я действительно не вижу этого.