J'ai un AsIterator
classe de modèle qui prend un numérique-comme le type, dans cet exemple juste un int
, et les convertit en un itérateur (++
et --
d'incrémentation et de décrémentation du nombre et operator*
retourne une référence).
Cela fonctionne très bien , sauf si elle est enveloppée dans une std::reverse_iterator
et compilé avec toute optimisation (-O
est suffisant). Quand j'optimiser le binaire, le compilateur se déshabille sur le déréférencement d'appel à l' reverse_iterator
et le remplace par un peu bizarre de la valeur. Il faut noter qu'il est toujours fait le bon nombre d'itérations. C'est juste la valeur obtenue par l'itérateur inverse, c'est-à ordures.
Considérons le code suivant:
#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;
}
Cela devrait supposé boucle vers le bas à partir de la plus haute inséré nombre le plus bas et de les imprimer, comme dans cette course (compilé avec -O0
):
Insert two integers: 1 4
3
2
1
Ce que je reçois avec -O
est plutôt:
Insert two integers: 1 4
1
0
0
Vous pouvez essayer en ligne ici; les chiffres peuvent varier, mais ils sont toujours "mal" lors de l'optimisation de la binaire.
Ce que j'ai essayé:
- coder en dur l'entrée des entiers est assez pour produire le même résultat;
- le problème persiste avec gcc 5.4.0 et clang 3.8.0, également lors de l'utilisation de la libc++;
- de faire de tous les objets
const
(c'est à dire de revenirconst int &
, et de déclarer toutes les variables en tant que tel) ne résout pas le problème; - à l'aide de l'
reverse_iterator
de la même manière, par exemple, certainsstd::vector<int>
fonctionne très bien; - si je viens d'utiliser
AsIterator<int>
pour une normale de l'avant ou vers l'arrière de la boucle, il fonctionne très bien. - dans mes tests, la constante
0
qui est imprimé est en fait codé en dur par le compilateur, les appels à l'printf
tous ressembler à ceci lorsqu'il est compilé avec-S -O
:
movl $.L.str.2, %edi # .L.str.2 is "%d\n"
xorl %eax, %eax
callq printf
Compte tenu de la consistance de clang et de la gccdans le comportement ici, je suis assez sûr qu'ils sont en train de faire et j'ai mal compris, mais je ne peux vraiment pas le voir.