Wiem, że zwiększenie lub kompilator powinien być ostatni, aby winić, ale nie widzę tutaj innego wyjaśnienia. Używam msvc 2008 SP1 i zwiększam 1,43.Potrzebujesz pomocy z BOOST_FOREACH/kompilatorem błędu
w kodzie następującym wykonanie urywka nigdy nie opuszcza trzeci pętla BOOST_FOREACH
typedef Graph<unsigned, unsigned>::VertexIterator Iter;
Graph<unsigned, unsigned> g;
g.createVertex(0x66);
// works fine
Iter it = g.getVertices().first, end = g.getVertices().second;
for(; it != end; ++it)
;
// fine
std::pair<Iter, Iter> p = g.getVertices();
BOOST_FOREACH(unsigned handle, p)
;
// fine
unsigned vertex_count = 0;
BOOST_FOREACH(unsigned handle, g.getVertices())
vertex_count++;
// oops, infinite loop
vertex_count = 0;
BOOST_FOREACH(unsigned handle, g.getVertices())
vertex_count++;
vertex_count = 0;
BOOST_FOREACH(unsigned handle, g.getVertices())
vertex_count++;
// ... last block repeated 6 times
kod Iterator:
class Iterator
: public boost::iterator_facade<Iterator, unsigned const,
boost::bidirectional_traversal_tag>
{
public:
Iterator()
: list(NULL), handle(INVALID_ELEMENT_HANDLE)
{}
explicit Iterator(const VectorElementsList &list, unsigned handle = INVALID_ELEMENT_HANDLE)
: list(&list), handle(handle)
{}
friend std::ostream&
operator<<(std::ostream &s, const Iterator &it)
{
s << "[list: " << it.list <<", handle: " << it.handle << "]";
return s;
}
private:
friend class boost::iterator_core_access;
void increment()
{
handle = list->getNext(handle);
}
void decrement()
{
handle = list->getPrev(handle);
}
unsigned const& dereference() const
{
return handle;
}
bool equal(Iterator const& other) const
{
return handle == other.handle && list == other.list;
}
const VectorElementsList<T> *list;
unsigned handle;
};
Niektóre ASM zabawa:
vertex_count = 0;
BOOST_FOREACH(unsigned handle, g.getVertices())
// initialization
013E1369 mov edi,dword ptr [___defaultmatherr+8 (13E5034h)] // end iterator handle: 0xFFFFFFFF
013E136F mov ebp,dword ptr [esp+0ACh] // begin iterator handle: 0x0
013E1376 lea esi,[esp+0A8h] // begin iterator list pointer
013E137D mov ebx,esi
013E137F nop
// forever loop begin
013E1380 cmp ebp,edi
013E1382 jne main+238h (13E1388h)
013E1384 cmp ebx,esi
013E1386 je main+244h (13E1394h)
013E1388 lea eax,[esp+18h]
013E138C push eax
// here iterator is incremented in ram
013E138D call boost::iterator_facade<detail::VectorElementsList<Graph<unsigned int,unsigned int>::VertexWrapper>::Iterator,unsigned int const ,boost::bidirectional_traversal_tag,unsigned int const &,int>::operator++ (13E18E0h)
013E1392 jmp main+230h (13E1380h)
vertex_count++;
// forever loop end
Łatwo zauważyć, że uchwyt iteratora jest buforowany w EBP i nigdy nie jest ts inkrementowane pomimo wywołania funkcji iteratora ++().
Zastąpiłem implantację Itarra jedną ze zmiennych pochodzących ze std :: iterator, a problem nadal występował, więc nie jest to błąd iterator_facade. Ten problem występuje tylko w kompilacjach wersji msvc 2008 SP1 x86 i amd64. Debugowanie odbywa się na msvc 2008, a kompilacje debugowania/wydania na msvc 2010 i gcc 4.4 (Linux) działają bez zarzutu. Ponadto blok BOOST_FOREACH musi zostać powtórzony tylko 10 razy. Jeśli jest powtórzony 9 razy, wszystko jest w porządku.
Domyślam się, że ze względu na BOOST_FOREACH użycie szablonowego oszustwa (const auto_any), kompilator zakłada, że uchwyt iteratora jest stały i nigdy nie odczytuje jego rzeczywistej wartości ponownie.
Byłbym bardzo szczęśliwy słysząc, że mój kod jest nieprawidłowy, popraw go i przejdź do BOOST_FOREACH, którego bardzo znajduję (w przeciwieństwie do BOOST_FOREVER :).
mogą być związane z: Why does BOOST_FOREACH not work sometimes with C++ strings?
EDIT:
Przygotowałem uproszczony projekt odtworzenia problemu. Bez szablonów, bez domyślnych parametrów, bez niczego. Pobierz: http://yabcok.nazwa.pl/ugly3.zip
Czy możliwe byłoby zapewnienie zestawu testowego do kompilacji? Czy próbowałeś porównać kod złożenia dwóch pętli z identycznym kodem C++? Fakt, że pętlę należy powtórzyć 10 razy, sugeruje, że może to być błąd kompilatora związany z optymalizacją. –
co się dzieje z 013E1392? –
przeskocz do 013E1380 - początek pętli na zawsze –